« October 2011 | Main | February 2012 »

January 28, 2012

Action, Func, void and unit

The .NET Framework defines two ‘standard’ delegate types: Action<> and Func<>.  The Func types are used for delegates that return values, and the Action types for those that don’t – in C# terms, for void methods.

This distinction can often be very annoying.  Consider a helper method such as:

public static T WithSomeResource<T>(Func<T> f) {
  AcquireSomeResource();
  try {
    return f();
  } finally {
    ReleaseSomeResource();
  }
}

This works fine when the thing you want to do returns a value:

int y = Helpers.WithSomeResource(() => x + 1);

But the compiler won’t let you pass anything that doesn’t return a value:

Helpers.WithSomeResource(() => Console.WriteLine(x));  // error

You have to create a separate overload that takes an Action instead of a Func, and has an identical implementation except for omitting the return keyword.  Granted, that’s not much work for a simple helper like the above, but what if it were more complicated?  Or what if you had a dozen of them?  Boring!  Also, maintenance nightmare!

The reason for this distinction is that although void sits in the position where you expect the return type to sit, and looks like a return type, it isn’t.  Visual Basic makes this much clearer by distinguishing between Sub and Function instead of abusing the return type identifier.  So in the WithSomeResource generic method, the type parameter T can’t be void, because void isn’t a type.  And so we end up needing the separate Action types, which do the job of Func<void>.

Contrast this with F#.  F# doesn’t have void: it has unit.  This may seem like it’s just a difference in naming, but it isn’t, because unit in F# is a real type.  A function that ‘doesn’t return a value’ in F# is considered to return type unit.

let f (s : string) = Console.WriteLine(s);; 
val f : string –> unit

So in F#, every function has a return type.  And therefore F# doesn’t need to distinguish between functions and actions.

let withSomeResource f = 
  acquireSomeResource() 
  try 
    f() 
  finally 
    releaseSomeResource();;
val withSomeResource : (unit –> 'a) –> 'a

The F# version of withSomeResource can be called interchangeably with ‘functions’ (that return real values) and ‘actions’ (that return unit) because unit is a valid type, and so the type parameter 'a can be unit just like any other type.

let y = withSomeResource (fun () –> x + 1);;  // okay 
withSomeResource(fun () –> Console.WriteLine(x));;  // also okay

Having unit instead of void makes it easier to write generic functions, because you don’t need to write separate implementations for the ‘value’ and ‘no value’ cases.

And that, my liege, is how we know the earth to be banana shaped.

January 28, 2012 in Software | Permalink | Comments (3) | TrackBack

January 25, 2012

Wellington .NET user group - Windows 8 for .NET developers

Thanks to everyone who came along this evening to watch me trying to get a wireless connection to work, and especially to those who stuck around for the Windows 8 talk afterwards. Here are the slides from the session, which in a rare departure for me actually contain the content of the talk instead of a series of gnomic Talking Heads references. Enjoy!

Windows 8 presentation slides

And although we didn't really have time to look at samples, you can get source code for the Metro sample apps I used here.

January 25, 2012 in Software | Permalink | Comments (0) | TrackBack