Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# implementation of interface method with type constraint

I have a stupid problem, I need to implement in F# class the interface which have following method:

public interface IMyInterface
{
    T MyMethod<T>() where T : class;
}

And I am struggling myself doing it in F#. I have tried different ways. But the problem is that an object of type T must be returned. Null is not accepted:

type public Implementation() = 
    interface IMyInterface with
        member this.MyMethod<'T when 'T : not struct>() = null

Error: The member 'MyMethod<'T when 'T : not struct> : unit -> a' when a': not struct and 'a: null does not have the correct type to override the corresponding abstract method. The required signature is 'MyMethod<'T when 'T : not struct> : unit -> 'T when 'T: not struct'

So I have tried to put T as argument to the class, but still no I finished with error:

type public Implementation(data : 'T when 'T : not struct) = 
    interface IMyInterface with
        member this.MyMethod<'T when 'T : not struct>() = data

Error: The member 'MyMethod<'T when 'T : not struct> : unit -> 'T when 'T : not struct' does not have the correct type to override the corresponding abstract method.

Thank you for help.

like image 745
user2323704 Avatar asked Jul 13 '16 17:07

user2323704


1 Answers

Instead of returning null (which is inferred to have some type 'a, check by returning null :?> 'T) you can use

type public Implementation() = 
    interface IMyInterface with
        member __.MyMethod<'T when 'T : not struct>() = Unchecked.defaultof<'T>

I prefer __ over this when it's not used.

TL;DR;

The class constraint in C# implicitly includes null. Unfortunately specifying that in F# is not allowed:

member __.MyMethod<'T when 'T : not struct and 'T : null>() = Unchecked.defaultof<'T>

results in:

The member 'MyMethod<'T when 'T : not struct and 'T : null> : unit -> 'T when 'T : not struct and 'T : null' does not have the correct type to override the corresponding abstract method. The required signature is 'MyMethod<'T when 'T : not struct> : unit -> 'T when 'T : not struct'.

But then, using classes and interfaces like these cross-language requires special attention anyways, because C# and the CLR allow null values whereas F# doesn't.

For comparison against null best overload F# isNull (see this answer):

let inline isNull (x:^T when ^T : not struct) = obj.ReferenceEquals (x, null)

unless your type allows null when you can use standard isNull:

[<AllowNullLiteral>]
type Foo() =
    member __.Bar() = ()

(Implementation() :> IMyInterface).MyMethod<Foo>() |> isNull // true
like image 104
CaringDev Avatar answered Oct 07 '22 10:10

CaringDev