Inheriting generic type parameters in interfaces

Topics: C# Language Design
Jul 23, 2014 at 4:46 PM
Since interfaces by definition have no implementation code, shouldn't it be possible to inherit from it's generic type parameters, as long as those parameters are also interfaces?
interface A {
    void methodFromA();
}
interface B<T> : T {
    void methodFromB();
}

class C : B<A> {
    public void methodFromA() {
    }
    public void methodFromB() {
    }
}
I do have specific use cases where this pattern would apply. All that would really be required is to enforce that the T has to be an interface type. This could be done implicitly (as above) or explicitly with a new generic constraint:
public interface B<T> : T
    where T : interface {
    void methodFromB();
}
Example use case:

I have written a BDD framework for C# that mimics jasmine's (js BDD framework) syntax. For those unfamiliar, you can write things like:
it("should comport to reality", function () {
    expect(0).toBe(0);
    expect(0).not.toBe(1);
});
To emulate this in C# is quite annoying:
// expectation.cs:
public interface IInvertible<T> {
    T Not { get; }
}
public interface IInvertibleIntegerExpectation<T> : IInvertible<IIntegerExpectation<T>, IIntegerExpection<T> {
}
public interface IIntegerExpectation<T> {
    void ToBe(T expected);
    // ...
}

// specification.cs:
IInvertibleIntegerExpectation<int> Expect(int actual) {
    // ...
}
This could be implemented a lot easier with the above:
// int32expectation.cs:
class Int32Expectation : IInvertible<IIntegerExpectation<int>> {
    IIntegerExpectation<int> Not {
        get { // ...
        }
    }

    public void ToBe(int expected) { // ...
    }
}

// specification.cs:
IInvertible<IIntegerExpectation<int>> Expect(int actual) {
    // ...
}
As I recall, typeScript allows this sort of behavior, and while it's not a CLR language, it proves that this sort of functionality is possible and desirable. Maybe I'm missing something, but I don't see any issues with this sort of inheritance. Perhaps something in the CLR prevents this?

I'm certainly not prevented from doing things the way I have been, but it would be a lot better to implement things with generic inheritance.
Jul 23, 2014 at 8:53 PM
I'm not 100% i understand the concept. What is the difference from this currently allowed pattern?
interface A
{
    void Foo();
}

interface B
{
    void Bar();
}

interface C : A, B
{
//combines the signatures of A and B
}

class Fizz : C
{
    void A.Foo() { } //explicit implementation is optional of course...
    void B.Bar() { }
}
Jul 24, 2014 at 2:33 PM
AlgorithmsAreCool wrote:
I'm not 100% i understand the concept. What is the difference from this currently allowed pattern?
C in your example (rightly so) is only a sort of composite interface type. If you know you're not going to add anything to C then why does it need to exist at all? So you might say, "I'll just remove C since it's redundant anyhow.", but once you do that, you can no longer return B and A at the same time, nor can you accept that in a function (unless you use a generic and add both interfaces as constraints, which is also redundant and hides your design intentions). If B can have dynamic inheritance, this problem goes away.

A case I thought of last night where this might be a little strange:
typeof(B<>).GetMethod("methodFromA"); // <-- not found
typeof(B<A>).GetMethod("methodFromA"); // <-- found
typeof(B<D>).GetMethod("methodFromA"); // <-- not found unless D inherits A
Another case that should produce a compiler error:
B<B<A>> someVar; // <-- B inherits from itself, this shouldn't be allowed.