When C#3 first came out, I thought that the type inference was awesome – you could do stuff like this:
Amazing, isn’t it? The C# compiler figures it all out for you!
Except there are other languages out there that are statically typed and yet have much more powerful type inference which cuts down on a lot of boilerplate coding for you, F# being one such language. Here’s some pseudo-C# examples of things that you simply can’t be done in the real C#..
Type inference of method parameters
In this example, I want the compiler to infer the types of the arguments being used in this method:
Obviously, C# won’t allow this, but here’s an F# equivalent which is perfectly legal: –
Notice how employeeName and employeeAge don’t have any explicit types against them. Once you’ve compiled this in F# interactive, you get the following:
i.e. printDetails takes in two parameters, string and int, and returns unit (read: void). This isn’t like generic resolution. In the example above, the compiler knows that employeeAge is typed as an integer because of the equality comparison with 31 (which is an integer). Similarly, the %s argument tells the compiler that employeeName is a string. In some ways this is reminiscent of lambda expressions which do away with the type declaration completely, except more powerful.
Now I’m no F# expert, but I think that you probably wouldn’t write even it like this in F#; you’d probably use a Tuple (think “a more flexible anonymous type” from C#) like this:
Same thing as before really, except here we take in a single parameter which is a Tuple of string and int; we treat the first bit as name and the second as age.
Sharing types across methods
Here’s another example of where type inference could be stronger in C#. I have two types, Customer and Employee. Both share a common property called Name, and I want a method to print that name out that can be shared across both types.
This PrintName method wouldn’t compile obviously, but if you wanted an all-purpose method like that to print out the name of a Customer or an Employee, you would need either: –
The creation of a common interface (say, INamedPerson, which Customer and Employee implement)
Use of C#4 dynamic and duck type it away
- In F#, the above sort of code is actually possible and perfectly legitimate – the PrintName method would be declared as taking in a tuple with the first parameter of Name and the second as an anonymous property. This is legal in F# because the type inference knows that the PrintName method only accesses the Name property, so it’s legal to use different types with it.
So the above example takes in a tuple parameter called person, which has two parts – the first is name, of type string, and the second is “something else”. It doesn’t know, or care, what the other bit is, because it’s not used in this method. The compiler calls it like so: –
i.e. string and an anonymous type ‘a (you get the same if you create an anonymous type in C# and mouse over the var). So now I can call it as follows: –
The first part in yellow above is my declaring a customer and an employee. The next bit is the compiler determining the type declarations of them. Then I call printName on both! Also note in the second example that there isn’t even a predefined Customer or Employee type – everything has been effectively done with anonymous types that simply are matched based on their type signature. Very cool!
Compare the C# and F# code samples above – the F# ones might seem a bit “uargh!” at first – almost as if they are weakly typed – but they aren’t; it’s just that the F# compiler is very, very smart and allows you to write very terse code such that you can do away with a lot of stuff that is, in fact, largely unnecessary.