Skip to content

Instantly share code, notes, and snippets.

@kasajian
Last active October 23, 2020 09:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kasajian/19e7c7cf717169da9c7acf82b6928254 to your computer and use it in GitHub Desktop.
Save kasajian/19e7c7cf717169da9c7acf82b6928254 to your computer and use it in GitHub Desktop.
promises

Promises

4557 We always imagine that a variable has a value. That is, as soon as a variable is created, it has some value, even if it's a default value. So if you have two variables, x and y, and you want to print the sum, you might code it this way:

WriteLine( x + y );

Now what if a variable's value doesn't exist right away, but will become available at some time in the future. The time in the future can be a long time, a short time or no time, but you don't know. The variable has a .Result property which will return the value, but blocking until the value is actually available. Let's say variable x is that type of a variable, so your code would now look like this:

WriteLine( x.Result + y );

In this case, if the value of x is not yet available, calling the .Result property will block until it becomes available. Once the value becomes available, then x is "resolved". After x is resolve, calling x.Result is immediate.

You can also write code that executes when the value becomes available. For example:

x.ContinueWith( xr => WriteLine( xr.Result + y ) ).Wait();

Same as before, if x is already resolved, the action is called immediately.

These types of deferred variables are called Promises ( https://en.wikipedia.org/wiki/Futures_and_promises )

How to create a Promise in C#

Let's create an int promise. You create a TaskCompletionSource:

`TaskCompletionSource<int> xTcs = new TaskCompletionSource<int>();`

The int value doesn't exist yet. The .Task property of the TaskCompletionSource holds the deferred variable that's used by the code that needs to access the eventual value. They don't need access to the actual TaskCompletionSource.

    Task<int> x = xTcs.Task;
    return x;

Than the client of that will call x.Result as described earlier.

At some future point to resolve the promise, the code that created the promise will call call SetResult' on the TaskCompletionSource`

xTcs .SetResult(15);

This resolves the promise. All code that was blocked by x.Result will become unblocked at this point. After that point, x.Result is immediate.

Exceptions You can also cause the promise to fail by calling the SetException() method instead of SetResult(). This will cause the exception to be propagated to clients awaiting on the promise. aa

When is this useful

Any time you have code that requires certain values to have already been retrieved (such as from a network or disk) or calculated (by async / code), using a promise ensures there's dependencies are handled automatically. If code requires a variable value to be resolve, then using a promise ensures that code that needs the value is executed when the actual value exists, and is not executed too early, using default data.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment