We may not have proper type class constraint support in F#, but we can still make sure our ‘square’ function doesn’t blow up at runtime.
Passing the Dictionary of Operations Explicitly
We found ourselves able to blow up our program at runtime with the following definition of our square function.
let square_numeric x =
let num = GetNumericAssociation<’a>()
num.Multiply(x,x)
let resulti = square_numeric 5
let resultf = square_numeric 5.0
let results = square_numeric “hello”
The fix for this is rather straightforward, although cumbersome for the user of our function. We force the user to pass the appropriate “dictionary of operations” into the function as the first parameter.
let square_numeric (ops : INumeric<’a>) =
let square x =
ops.Multiply(x,x)
square
let resulti = square_numeric Instances.Int32Numerics 5
let resultf = square_numeric Instances.FloatNumerics 5.0
We can no longer pass a string into the function as the type of the dictionary will constrain our parameter.
let resultf = square_numeric Instances.FloatNumerics “hello”
The compiler complains that the type string cannot be used as a float. With true type class support, the explicit passing of dictionaries would be unnecessary. For Instance,
let square_numeric (x => NumericInstances) = Multiply(x,x)
let result_int = square_numeric 5
would result in the compiler implicitly passing the Int32Numerics dictionary of operations into our function. This is what Haskell does and the designer’s of F# expect a future version of the language will support this.
Inline the Function
The Inline keyword is used to support operator overloading. This same mechanism can be used to perform duck typing. This duck typing behavior enables us to write a function that accepts any type that supports the (*) operator.
let inline square_inline (x : ^x) = x * x
let resulti = square_inline 5
let resultf = square_inline 5.0
let results = square_inline “hello”
The first two declarations work, but the last results in the compiler letting us know “The type ‘string’ does not support any operators named ‘*’. The inline and (^) hat syntax statically constrains the type to only those with the designated member.
This constraint is static since the inline keyword behaves much like C++ templates. The compiler expands each definition into its own separate function at compile time. The CLR has built in support for usual generic functions and does not expand these until runtime. The benefits of this approach are documented here.
So Which Way is Best?
I would stick with passing the dictionary of operations around explicitly. Hopefully, F# will add type class support sooner rather than later. Sure, you’ll have to rewrite some code, but at least conceptually the compiler will be doing what you’re currently doing explicitly. As for the inline method, I can’t recommend compile time expansion of generic code as a general purpose practice. The ability to do this is cool, but I’d wait for some better guidance from the experts before writing all your functions this way.

Thanks Matt.
I’m learning F#, this helps; looking for more.
I’ve run into a new word/concept/theoretical result: Parametricity (tongue-tie’r).
Wikipedia’s entry mentions Haskell.
I saw parametricity first in Guy Cousineau’s works on OCaml.
It’s a beautiful thing, it helps structure generality and thus generic programs… yet seemingly illusive (t’was always thus).
Art,
You can find a very recent addition to F# that builds upon the notion of relational parametricity.
http://blogs.msdn.com/andrewkennedy/archive/2008/08/20/units-of-measure-in-f-part-one-introducing-units.aspx
There is one consequence of passing the operations as a dictionary that you didn’t discuss. Namely performance. Your code uses INumerics as the type of the dictionary. I’m assuming that’s an interface. Calls via an interface are very expensive as compared to an inline operator. Namely because the CLR can do no optimizations on an interface method.
In normal circumstances, the cost of using an interface is negligable. But if you’re building a set of math libraries this could quickly add up and create a big performance issue. As always a benchmark should be done to test the relative win/loss.
My 2 cents is go the inline route. It’s more natural and type safe. I’m not 100% familiar with F# inline so I don’t really understand the down sides to inline or the constraints.
Good points Jared. Library writers have a different set of challenges from library consumers. You’ve raised my interest in how the Math library for F# is implemented. The type class for Numerics is generated by the Math library so I’m assuming it’s used internally by the F# math routines.
[...] sugaring. Others have taken different angles such as such as with simple operators and template expansion, but in this case, I don’t think that’s enough to help. Instead, it’s best to use the [...]