views:

340

answers:

2

In C#, I can implement a generic interface twice on one class, using two different type-parameters:

interface IFoo<T> { void Foo(T x); }

class Bar : IFoo<int>, IFoo<float>
{
    public void Foo(int x) { }
    public void Foo(float y) { }
}

I would like to do the same thing in F#:

type IFoo<'a> = abstract member Foo : 'a -> unit

type Bar() =
    interface IFoo<int> with 
        [<OverloadID("int")>]
        member this.Foo x = ()

    interface IFoo<float> with 
        [<OverloadID("float")>]
        member this.Foo x = ()

But it gives a compiler error:

"This type implements or inherits the same interface at different generic instantiations
 'IFoo<float>' and 'IFoo<int>'. This is not permitted in this version of F#"

I can't find any discussion of this issue on the web. Is such use frowned upon for some reason? Are there plans to allow this in an upcoming release of F#?

+4  A: 

Right now I don't know of plans to allow this.

I think the only reasons its currently disallowed are that it's non-trivial to implement (especially with F# type inference), and it rarely arises in practice (I only recall one customer ever asking about this).

Given an infinite amount of time and resources, I think this would be allowed (I can imagine this being added to a future version of the language), but right now it does not seem like this is a feature worth the effort of supporting. (If you know a strong motivating case, please mail [email protected].)

EDIT

As an experiment for the curious, I wrote this C#:

public interface IG<T>
{
    void F(T x);
}
public class CIG : IG<int>, IG<string>
{
    public void F(int x) { Console.WriteLine("int"); }
    public void F(string x) { Console.WriteLine("str"); }
}

and referenced it from F# (with comments suggesting the results)

let cig = new CIG()
let idunno = cig :> IG<_>  // type IG<int>, guess just picks 'first' interface?
let ii = cig :> IG<int>    // works
ii.F(42)                   // prints "int"
let is = cig :> IG<string> // works
is.F("foo")                // prints "str"

so this is what typically happens on this 'boundary' stuff with F# - F# can consume this stuff ok, even if you can't author the same stuff from within the language.

Brian
Er, so how would F# type inference deal with such types written in C#, then? As for rationale, well... ECMA CLI specs defines various categories of CLS compliance; one of them is "CLS extender". One requirement for that is: "Able to... Implement any CLS-compliant interface."
Pavel Minaev
To expand on Pavel's comment, what happens if you define a non-generic interface `I` in C# which extends both `IG<int>` and `IG<string>`? Can this interface be implemented from within F#?
kvb
@kvb, no, that interface cannot be implemented from F#.
Brian
A: 

This issue is (or appears to be) a show stopper for me using my favorite ORM with F#. Not to mention, vice versa. I am using DataObjects.NET by Xtensive (www.x-tensive.com) and in order to consume their (totally awesome) persistence API, my domain objects have to inherit, sensibly enough, from Entity, which happens to implement an interface with two generic instantiations somewhere in the little black box. So, merely sub-classing Entity is a total no-can-compile situation.

This is not an answer to the question.
Gabriel