interfacef#

F# Interface with static member


How to define a static member in an Interface?
Why it is not possible?

I want to force a F# type (class) to have a static method to create an instance of itself from a string (JSON parsing). I want this Interface example:

[<Interface>]
type public ILikeJson<'T> =
    abstract member ToJson: unit -> string         // OK
    static abstract member FromJson: string -> 'T  // <-- "static" is not valid here !

Alternatively a constructor from a string can do the work but a static method sounds better because it will have an appropriate name and I don't know how to define a constructor in the Interface too.


Solution

  • The present CLR specification states that interfaces are only implemented for object instances and do not apply for the types themselves.

    C# 8 has a proposal for defining static interface members, but it is required to provide an implementation for the static methods within the interface definition itself. So you won't be able to implement a FromJson method per class.

    If you try this in F#, you'll get:

    FS0868: Interfaces cannot contain definitions of concrete members. You may need to define a constructor on your type to indicate that the type is a class.

    One solution to this problem is to use static type constraints. They allow you to look up the existence of a method on a type.

    let inline create< ^T when ^T : (static member FromJson: string -> ^T)> json = 
         (^T : (static member FromJson: string -> ^T) (json))
    

    This supports any type which has a static method FromJson with the string -> T signature.

    type Number(num: double) =
        member _.Value = num
        static member FromJson (json) = new Number(Double.Parse(json))
    

    and to use:

    create<Number> "1.5" //creates a Number(1.5)