Question

I'm trying to create a function in FSharp that will take a parameter of an interface type and a parameter of a derived type, which passes on both parameters as implementations of that interface:

Simplified example:

type IFoo =
    abstract member Compare : IFoo -> bool

type Foo =
    interface IFoo with
        member this.Compare _ = false

let doCompare (a : IFoo) (b : IFoo) = a.Compare(b)

let comp  (x : IFoo) (y : #IFoo) = doCompare x (y :> IFoo)
let comp2 (x : 'T)   (y : #'T)   = doCompare x (y :> 'T)

I'm getting the following two errors on the generic version (here, comp2):

On the parameter:

This construct causes code to be less generic than indicated by its type annotations. 
The type variable implied by the use of a '#', '_' or other type annotation at or near '...' 
has been constrained to be type ''T'.

On the cast operator:

The static coercion from type 'T to 'T involves an indeterminate type based on information prior to this program point. 
Static coercions are not allowed on some types. Further type annotations are needed.

Is there a way I can fix this, other than creating a signature using 'T 'U and casting via object which is obviously unsafe ?

This code (together with the original code that showed this problem - which is for wrapping NSubstitute in a test fixture) is available on tryfsharp

Was it helpful?

Solution

The # is syntactic sugar for a subtype constraint, ie. comp2 is equivalent to:

let comp2<'T, 'U when 'U :> 'T> (x:'T) (y:'U) = doCompare x (y :> 'T)

Unfortunately, the 'U :> 'T part is not supported by the type system (you cannot constrain a type to be a subtype of a type variable), so this is not possible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top