After reading Eric Lippert’s answer I got the impression that await
and call/cc
are pretty much two sides of the same coin, with at most syntactic differences. However, upon trying to actually implement call/cc
in C# 5, I ran into a problem: either I misunderstand call/cc (which is fairly possible), or await is only reminiscent of call/cc.
Consider pseudo-code like this:
function main:
foo();
print "Done"
function foo:
var result = call/cc(bar);
print "Result: " + result;
function bar(continuation):
print "Before"
continuation("stuff");
print "After"
If my understanding of call/cc is correct, then this should print:
Before
Result: stuff
Done
Crucially, when the continuation is called, the program state is restored along with the call history, so that foo
returns into main
and never comes back to bar
.
However, if implemented using await
in C#, calling the continuation does not restore this call history. foo
returns into bar
, and there’s no way (that I can see) that await
can be used to make the correct call history part of the continuation.
Please explain: did I completely mis-understand the operation of call/cc
, or is await
just not quite the same as call/cc
?
Now that I know the answer, I have to say that there’s a good reason to think of them as fairly similar. Consider what the above program looks like in pseudo-C#-5:
function main:
foo();
print "Done"
async function foo:
var result = await(bar);
print "Result: " + result;
async function bar():
print "Before"
return "stuff";
print "After"
So while the C# 5 style never gives us a continuation object to pass a value to, overall the similarity is quite striking. Except that this time it’s totally obvious that "After" never gets called, unlike in the true-call/cc example, which is another reason to love C# and praise its design!