Maik Klein
Maik Klein

Reputation: 16148

Generic constructors in F#

type Foo(size: int,data: 'T []) =
    new(data: float []) =
        Foo(sizeof<float>,data)
    new(data: int []) =
        Foo(sizeof<int>,data) //error: f# thinks that data is float []
    member this.Size() = size

Basically I need several constructors with a generic array 'T [] and I only care for the size of 'T.

I want to use it like this:

Foo([|1,2,3,4|]).Size() // prints size of int
Foo([|1.f,2.f,3.f,4.f|]).Size() // prints size of float

How would I do this?

Update1:

I just realized that I can't let the compiler infer the size, I have to do this manually.

type Foo<'T>(size: int,data: 'T []) =
    new(data: float []) =
        Foo(4,data)
    new(data: int []) =
        Foo(16,data)
    new(data: Vector3 []) =
        Foo(Vector3.SizeInBytes,data)
    member this.Size() = size

Would this be possible?

When I do Foo([|new Vector3(1.f,1.f,1.f)|] I want Foo to be of Foo<Vector3> and therefore data should be of type data: Vector3 []

Upvotes: 2

Views: 277

Answers (1)

p.s.w.g
p.s.w.g

Reputation: 148980

Try this:

type Foo<'T>(size: int, data: 'T []) =
    new(data: 'T []) =
        Foo(sizeof<'T>, data)
    member this.Size() = size

Note that you should take care when testing this. When you call Foo([|1,2,3,4|]), it infers that the the type T is int * int * int * int. Use semicolons to separate array elements:

Foo([|1;2;3;4|]).Size()           // 4
Foo([|1.f;2.f;3.f;4.f|]).Size()   // 4
Foo([|1.m;2.m;3.m;4.m|]).Size()   // 16

Update
Given your updated question, it appears you're trying to do a bit of partial specialization. I'd recommend not trying to do this within the generic class itself, after all, the whole point of generics in .NET is that you should not have to have different strategies for each type you want to use. Instead, create a separate type with static factories for generating your Foo objects with multiple overloads for the various types you'd like to create:

type Foo<'T>(size: int, data: 'T []) =
    member this.Size() = size

type Foo =
    static member from (data : int[]) = Foo(16, data)
    static member from (data : float[]) = Foo(4, data)
    static member from (data : Vector3[]) = Foo(Vector3.SizeInBytes, data)
    static member from (data : 'T[]) = Foo(sizeof<'T>, data)

Foo.from([|1;2;3;4|]).Size()                // 16
Foo.from([|1.f;2.f;3.f;4.f|]).Size()        // 4
Foo.from([|Vector3(1.f,1.f,1.f)|]).Size()   // Vector3.SizeInBytes
Foo.from([|1.m;2.m;3.m;4.m|]).Size()        // 16

Upvotes: 2

Related Questions