Wednesday 12 October 2011

Creating a class with multiple constructors in F#

Using the implicit type syntax couldn't be easier. For example:


type A (a,b) as this =
let c = "sum"
do printfn "The sum is " (a+b)


Easy! But class A only has one constructor. Suppose we want another? The obvious guess would be


type B (a,b) as this =
let c = "sum"
do printfn "The sum is " (a+b)
new (d) = B(a,0)


but this doesn't work for a number of reasons. You can't have let or do sections in your type if you have multiple constructors. So this means that a, b and c have to be defined in the new function. This means, of course, that you need to use explicit class syntax. The action can then follow the initialisation in a then clause.


type C =
val a :float
val b :int
val c :string
new (_a,_b) = { a=_a; b=_b; c="sum"} then printfn "The sum is " (a+(float b))
new (_a) = { a=_a; b=0; (* Yes, you have to initialise all the class members *) c="sum"} then printfn "The sum is " (a+(float b))


Whew! Complicated! And repetitive, potentially! It is possible to call functions in the then clause but you still have to initialise all the members in the record clause.

It's more fiddly in the presence of inheritance unfortunately. In this case the record initialiser has to include inherit Cbase(a).

Here's one I've used in production code, anonymised...


type drv = class
inherit bse

val _parser : Parser
val _columnExtractors : List

new (configuration:ExpConfig ) as x =
{inherit bse(configuration); _parser = new Parser(configuration); _columnExtractors = new List()}
then x.Init()
new (configuration:ExpConfig, parser:Parser) as this =
{inherit bse(configuration); _parser = parser; _columnExtractors = new List()}
then this.Init()

member private x.Init() =
printfn "blah blah blah"
end

No comments:

Post a Comment