I wrote about continuation-passing style in a post a couple of months ago, and I’ve had time to ruminate over it since. One consideration I had is whether to return a type or not. This is easily handled by overloading the method.
static void Main()
{
var result = Div(16, 3, (q, r) => new { Quotient = q, Remainder = r });
Console.WriteLine("quotient: {0}", result.Quotient);
Console.WriteLine("remainder: {0}", result.Remainder);
Div(20, 3, (q, r) => Console.WriteLine("\nquotient: {0} \nremainder: {1}", q, r));
}
public static T Div<T>(int dividend, int divisor, Func<int, int, T> func)
{
Contract.Requires(divisor != 0);
Contract.Requires(func != null);
var quotient = dividend / divisor;
var remainder = dividend % divisor;
return func(quotient, remainder);
}
public static void Div(int dividend, int divisor, Action<int, int> action)
{
Contract.Requires(divisor != 0);
Contract.Requires(action != null);
var quotient = dividend / divisor;
var remainder = dividend % divisor;
action(quotient, remainder);
}
The first block of code inside of the Main method returns an anonymous type with Quotient and Remainder properties that are then printed to the screen. The second block passes the continuation action to the method. The purpose of the second version is create side-effect, in this case I’m writing to the screen, but in C# world this is sometimes necessary and beats the uglier code you will end up with if you attempt to do it with the function type.
But is the action really necessary? In my mind, Action<int, int> should be the same thing as Func<int, int, void>. I posted a message about this on twitter, and received a response that return type can’t be nothing. But here’s the rub… void isn’t nothing. The void keyword actually refers to the System.Void type. When you define a void method and return out of it, it returns a Void. This is object-oriented land, everything is an object; even void.
It would be neat if this could work as there would be no need for an action overload. If the lambda performed an action, void would be returned automatically. Basically, with void functions the second block of code in Main would make the second call have the following calling signature (with T replaced):
public static void Div<void>(int dividend, int divisor, Func<int, int, void> func)
This works great for generic continuation-passing methods. This actually works fine for any type of generic method with a tail function (a tail function is at the end). Upon further thought, I realized it’s terrible when the function wasn’t the tail.
If this were to exist, what would you do if someone were to assign a variable within the method?
public static void WriteDiv<T>(int dividend, int divisor, Func<int, int, T> func)
{
Contract.Requires(divisor != 0);
Contract.Requires(func != null);
var quotient = dividend / divisor;
var remainder = dividend % divisor;
var ret = func(quotient, remainder);
Console.WriteLine(ret);
}
I suppose ret would be an instance of System.Void, but what does it mean to write a void, which is nothing? It’s not the same as null… is more nothing than null. In fact, it can’t even be null because, well, it’s a struct.
Despite the fact it’s probably a bad idea, I attempted the impossible anyway. The C# compiler does not like you using System.Void, and it will not allow you to define void inside of generic parameters. So, I modded some IL!
Download the files
It assembles fine, and you can see it in reflector. However, I receive a runtime error when running it.
Unhandled Exception: System.TypeLoadException: The generic type 'System.Func`2' was used with an invalid instantiation in assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. at VoidFuncs.Program.Main()
It’s probably for the best that it doesn’t work. Any suggestions on how to make it work? I’m particularly looking for semantics as I believe that this could help promote functions to be first class citizens in C#.