Search

Allow to implement same generic interface for more that one type parameter in generic class under some conditions by TAG

Closed
as By Design Help for as By Design

7
0
Sign in
to vote
Type: Suggestion
ID: 91817
Opened: 12/26/2004 2:00:50 PM
Access Restriction: Public
1
Workaround(s)
Currently then user trying to declare something like a:

using System.Collections.Generic;

public sealed class NullableCollection<TStruct, TInterface>
: ICollection<TStruct?>,
ICollection<TStruct>,
ICollection<TInterface>

    where TInterface : class
    where TStruct : struct, TInterface { // Some methods here }

He recieve an error:

error CS0695: 'NullableCollection<TStruct,TInterface>' cannot implement both 'System.Collections.Generic.ICollection<TInterface>' and 'System.Collections.Generic.ICollection<TStruct?>' because they may unify for some type parameter substitutions

But in same time - such a unify situation are only tiny subset of possible type arguments.
As well - such kind of unification can cause NO problems.
Details (expand)
Product Language
English
Version
Community Technology Preview October 2004
Category
Language/Compiler
Operating System
Windows Server 2003
Operating System Language
US English
Proposed Solution
Allow to specify such a inheritance at definition time - but ban limited set of "unified" arguments at usage time.

In general:
I would like all possible usage scenarios will be allowed for generics. This is one of them.
As well - this can be possible to define user-specific restrictions for type-arguments.

I believe that current compile-time CS0695 error limit area of usage of generics for more that one-argument scenarios.

I hope somebody from language design team will clarify why this error detected at compile-time - not at binding one.
This is completely legal usage scenario of generics. As well restriction to ban "unified" type arguments are legal too - in case if they clash - then instead of 2 (or N) typearguments - 1 (or >=N-1) argument generic class must be used.

Thanks in advance
Benefits
Faster Development
Improved Reliability
Other Benefits
Faster Development
File Attachments
0 attachments
Sign in to post a comment.
Posted by naasking on 11/12/2011 at 1:47 PM
I agree with mark n and TAG. With the current behaviour, you can't even implement a class that accepts a stream of two values T0 and T1 by implementing class Foo<T0, T1> : IObvservable<T0>, IObservable<T1> because T0 and T1 may unify. Whether T0 and T1 unify is *irrelevant* to whether this is well-typed.

Certainly there are *some* cases where unification is nonsensical, but there are plenty where it makes perfect sense. I can provide numerous examples.
Posted by mark n on 12/7/2007 at 2:09 AM
I've changed my mind....there (should be) absolutely nothing wrong with unification, and implementing the same interface twice is logically valid, and should be allowed in general. As long as the object satisfies it's contract it is (functionally) irrelevant which implementation is actually used to do so, this is really the basic tenet of OO programming, so if the interfaces unify then the compiler is at liberty to choose whichever implementation it wishes....it would seem sensible to have a hard and fast rule, e.g. it chooses the first one.
Posted by mark n on 12/6/2007 at 3:50 AM
I have a similar problem....

interface IA<T1> {}

interface I2A<T1,T2> : IA<T1>,IA<T2>
{
}

I'm not sure whether I believe (probably because I do not completely understand).....the reasoning in the comment about it being
a) complexity of algorithm
b) a type implementing another interface in the future.

I would suggest the solution of;
a) allowing the construct, and checking for the unification in the type instantiation, rather than the declaration (if you see what I mean)
b) creating a new 'where' clause of 'not'...though this may be an interesting can of worms....but

interface I2A<T1,T2> : IA<T1>,IA<T2> where T1 !: T2
{
}


Posted by Microsoft on 1/19/2005 at 9:08 AM
Hi Tag,
the whole point of generics is the compile type safety. We are willing to prevent some scenario from working to achieve it.
Posted by TAG on 1/11/2005 at 2:36 PM
As for my original goal is to create a workaround for covariant/contravariant generics.

I'm willing to be able pass instance of single object to methods that will expect ICollection<TStruct> or ICollection<TStruct?>.

As well - I'm willing to get some performance savings to avoid wrapping real TStruct objects into TStruct? before method calls.

As for unification - I'm offering to change this error to warning - and throw runtime exception if user trying to instantiate generics with params that will unify.
Just like current BindGenericArguments do if you pass wrong arguments.

Example:
    class Test<TStruct> where TStruct : struct { }
    class Program
    {
        static void Main(string[] args)
        {
            Type t = typeof(Test<>);
            t.BindGenericParameters(typeof(Program));
        }
    }
This will result in ArgumentException.

Thanks in advance
Posted by Microsoft on 1/11/2005 at 12:18 PM
Hi, thanks for logging this.

The algorithm for deciding which types unify becomes quite complex when you consider all the permutations of possible constraints. In many cases it is not even doable because the type system is unbounded and you don't really know if there will ever be a case in the future when a particular type won't implement a certain interface (for example). This begs the question of which cases our algorithm should recognize and which cases it shouldn't. As we often do, we opted for simplicity and we decided not to consider constraints in the unification (or the applicability) algorithm (as 20.3.1. in the spec describes).

As a curiosity note, what are you trying to achieve by making your class inherit from ICollection<TStruct> and ICollection<TStruct?>?
Sign in to post a workaround.
Posted by Qwertie on 2/5/2012 at 10:20 AM
This blog post proposes a workaround for some cases:

http://higherlogics.blogspot.com/2011/11/type-unification-forbidden-more-cclr.html