Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing the same interface at different generic instantiations

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#?

like image 823
Gabriel Avatar asked Sep 23 '09 05:09

Gabriel


People also ask

Can a class implement different instantiations of the same generic interface?

It is prohibited that a type implements or extends two different instantiations of the same interface. This is because the bridge method generation process cannot handle this situation.

Can we implement COM interface twice?

A class can implement more than one interface at a time. A class can extend only one class, but implement many interfaces. An interface can extend another interface, in a similar way as a class can extend another class.

Can a generic implement an interface?

Only generic classes can implement generic interfaces. Normal classes can't implement generic interfaces.


1 Answers

Right now I don't know of plans to allow this.. The feature has been planned and is, at least partially (see comments) implemented in F# 4.0.

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.

like image 125
Brian Avatar answered Sep 20 '22 22:09

Brian