genericsinterfacef#operators

Instantiation of type with recursive type constraints


The Announcing F #7 page gives the example code

type IAddition<'T when 'T :> IAddition<'T>> =
    static abstract op_Addition: 'T * 'T -> 'T

type Number<'T when IAddition<'T>>(value: 'T) =
    member _.Value with get() = value
    interface IAddition<Number<'T>> with
        static member op_Addition(a, b) = Number(a.Value + b.Value)

How do you instantiate a value of type Number? It would seem you have to pass a generic argument of some type MyType that implements IAddition<MyType>. But then from the IAddition definition, MyType also has to implement IAddition<MyType>, and so on. So how do you get off the ground?

Also, what is the difference between 'T when 'T :> IAddition<'T> and 'T when IAddition<'T>? I can't find documentation on this.


Solution

  • The Number class in this example is a bit pointless, since it does nothing but reimplement addition, but here's an example that shows how it can be instantiated:

    type MyType = MyInt of int with
        interface IAddition<MyType> with
            static member (+)(MyInt a, MyInt b) =
                MyInt (a + b)
    
    let x = Number(MyInt 1)
    

    Note that MyType implements IAddition<MyType>, which means it can be wrapped via Number. As Fyodor mentioned, there is no infinite regress.

    As far as I know, there is no difference between 'T when 'T :> IAddition<'T> and 'T when IAddition<'T>, but I could be wrong. The second form is not well documented, I think.