CSharp/C# >> Generics, Interfaces, and Inheritance question

by -- » Fri, 22 Aug 2008 01:29:12 GMT

Imagine I have a class TypeX and a class TypeY that inherts TypeX.
public class typeX
{
...
}

public class typeY
: typeX
{
...
}

I also have an interface IX
public interface IX
{
typeX GetThing();
void SetThing(typeX x);
}

And a generic class ABC that implements IX and is defined like so
public class ABC<T>
: IX
where T : typeX
{
T val;
public T GetThing(){return val;}
public void SetThing(typeX x){val = x;}
}

Why is this code not valid? ABC<T> does implement the interface, due
to the fact that T must be of typeX (or derived from it)

CSharp/C# >> Generics, Interfaces, and Inheritance question

by Peter Morris » Fri, 22 Aug 2008 01:40:31 GMT


> public T GetThing(){return val;}

if you create ABC<TypeY> then this signature is

public TypeY GetThing();

which does not match your interface declaration. You could make your
interface generic


IX<T>
{
T GetThing();
void SetThing(T x);
}



Pete

CSharp/C# >> Generics, Interfaces, and Inheritance question

by -- » Fri, 22 Aug 2008 04:48:41 GMT


But typeY is a typeX, so it still fulfills the contract of the
interface.

CSharp/C# >> Generics, Interfaces, and Inheritance question

by Peter Duniho » Fri, 22 Aug 2008 07:25:01 GMT


An object of that type can be used to fulfill the contract, but only typeX
itself can fulfill the contract _as a return type_. Since methods aren't
variant by return type, a method that returns a type that inherits typeX
is not the same as a method that the type typeX exactly, and so there's no
way at compile time for the compiler to be sure that your class method
actually implements the interface's contract.

You could fix it by making the interface generic, but it seems to me you
could just change the return value for the GetThing() method to be the
correct type: typeX. That is:

class ABC<T> : IX where T : typeX
{
T val;
public typeX GetThing() { return val; }
public void SetThing(typeX x) { val = x; }
}

Now, all that said, you have a problem in your SetThing() method
declaration as well. That is, even though there you did declare the
method with the actual type rather than the type parameter, the field
"val" is incompatible with "x" in the method and you should be getting an
compiler error there too.

That error is actually worse, because there's no guarantee that any
arbitrary reference to an object of typeX will in fact be an object of
type T. So, you could explicitly cast the "x" to match the type T, but
then you'd just wind up removing the whole point of having the generic
class by casting away the type safety that generics provide.

Basically, given the interface you've got, it's not clear at all that it
makes any sense whatsoever to implement it with a generic class. The
interface requires that the class allow setting using an object of any
type that inherits typeX, but your generic class can be used in a concrete
way where the actual type is more restricted (i.e. is some more-derived
type).

So, if you also had typeZ that inherits typeX but declared a usage of
class ABC<T> with typeY, if you could get the code to compile you'd have
the possibility of trying to store an object of typeZ in a variable of
typeY, which would not be allowed. It'd throw a run-time exception,
assuming you wrote the code so that it compiled in the first place.

Given that the basic design seems to be broken, this may be irrelevant,
but...I'll take as granted that you have a good reason for why that
pattern isn't a property instead of two explicit methods. :)

Pete

CSharp/C# >> Generics, Interfaces, and Inheritance question

by -- » Wed, 27 Aug 2008 03:35:18 GMT

This wasn't a real world example, just an attempt to simplify the
question and understand what was going on. No actual code was written
or harmed in the creation of this post.
The SetThing method should have been:
public void SetThing(T x) { val = x; }

> Given that the basic design seems to be broken, this may be irrelevant, ? > but...I'll take as granted that you have a good reason for why that ? > pattern isn't a property instead of two explicit methods. ?)

Again, it's because it was just something to show the problem, in the
real world it would be a property.

I think the primary issue is the return type invariance that's driving
me nuts. I'm not certain I understand why c# has that constraint.
With the introduction of the var keyword, it seems the compiler should
be able to determine the correct function, like python's or haskell's
type inference.

CSharp/C# >> Generics, Interfaces, and Inheritance question

by Jon Skeet [C# MVP] » Sat, 30 Aug 2008 03:28:18 GMT


<snip>


Return type invariance is a completely separate matter to type
inference. It's a matter of interface compatibility (even when just
classes are involved). I don't *think* that .NET itself supports return
type covariance, as opposed to (say) Java where the JVM has supported
it for a long time, and it became available through the Java language
in v1.5.

And yes, I'd really like it myself on occasion - in particular, the
Java to C# port I've been doing recently would have been *much* nicer
with covariant return types.

--
Jon Skeet - < XXXX@XXXXX.COM >
Web site: http://www.pobox.com/ ~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com

CSharp/C# >> Generics, Interfaces, and Inheritance question

by Pavel Minaev » Sun, 31 Aug 2008 16:37:17 GMT


CLR doesn't indeed support invariance as such, but it can be emulated
close enough with explicit overrides:

class Base
{
virtual IBase Foo() { ... }
}

class Derived
{
virtual IBase Base.Foo() { return Foo(); }
virtual IDerived Foo() { ... }
}

The above is illegal in C#, of course - that only allows explicit
implementation of interface methods - but CLR itself allows to rename-
override any virtual method of any base class, interface or not, so
some future version of the C# compiler could conceivably use this
trick to provide covariance on language level without CLR changes.

CSharp/C# >> Generics, Interfaces, and Inheritance question

by Anders Borum » Wed, 03 Sep 2008 17:29:28 GMT

Hello!


Return type covariance is something more and more developers are asking for,
so let's hope somebody from the C# team announces support for this at PDC
later this year. I remember a C# team member stating that this feature
requred changes to the CLR - perhaps he was wrong or didn't want to make it
sound as if it would be "easy".

Regardless, it would really make our lives a lot easier.

--
With regards
Anders Borum / SphereWorks
Microsoft Certified Professional (.NET MCP)

CSharp/C# >> Generics, Interfaces, and Inheritance question

by Pavel Minaev » Thu, 04 Sep 2008 13:52:04 GMT


Hope is always there, but I don't have much of it, to be honest. A lot of
Connect feature request tickets were closed some time ago with the following
comment from the C# PM:

"We have to do some harsh prioritization, both because of our implementation
and testing resources, but also because we need to keep the number of new
langauge features at a manageable level - depending on how you count, we are
adding only four language features to C# this time around. "

So, 4 new features. We can safely assume that one of those is generic
variance. That leaves 3, and if they count every new construct as a feature,
that doesn't leave much.


It does require changes to CLR to do it properly, most certainly. What I've
described earlier was just a hack that sort of does the same thing.

Then again, they are actually changing the CLR for 4.0, as I understand, so
anything is possible...

CSharp/C# >> Generics, Interfaces, and Inheritance question

by Anders Borum » Thu, 04 Sep 2008 19:15:35 GMT

Hi Pavel,


I've been following Eric Lipperts blog
( http://blogs.msdn.com/ericlippert/default.aspx ) and his series on support
for generic variance in a hypothetical future version of C#. It seems like
the Eric has spent a great deal of time pondering over how to add support
for generic variance (obviously without any announcements), and I'm
wondering why you'd "safely assume that one of those is generic variance".

I mean, there has been a lot of requests for this feature in the community,
but it would seem like the C# team (according to channel 9 videos etc.) is
focusing on adding support for parallelism (immutability) etc. I think
adding support for generic variance would make a really big difference to C#
developers, because API designs get much more simple (and elegant).

--
With regards
Anders Borum / SphereWorks
Microsoft Certified Professional (.NET MCP)

CSharp/C# >> Generics, Interfaces, and Inheritance question

by Jon Skeet [C# MVP] » Thu, 04 Sep 2008 19:30:01 GMT


From http://blogs.msdn.com/ericlippert/archive/2008/05/07/covariance-
and-contravariance-part-twelve-to-infinity-but-not-beyond.aspx

"As I've discussed at length in this space, we are considering adding
covariance and contravariance on delegate and interface types
parameterized with reference types to a hypothetical future version of
C#."

Not a firm commitment, but I think there's enough evidence that the C#
team have spent a lot of time on this to suggest it'll be in C# 4.


I strongly suspect we'll see *some* variance as described above
(delegates and interfaces), but that doesn't mean covariant return
types necessarily. I'd love it too, mind you.

--
Jon Skeet - < XXXX@XXXXX.COM >
Web site: http://www.pobox.com/ ~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com

CSharp/C# >> Generics, Interfaces, and Inheritance question

by Anders Borum » Thu, 04 Sep 2008 20:18:48 GMT

Hi Jon, et al.




Lots of qualified feedback was provided in the comments on the variance
series and judging from the suggested syntax I'd say the picture seems quite
complete already.
PDC would be a great place to make announcements; hopefully with the release
of a beta of C# 4 for immediate release (that would mean I'd have to thank
the team personally).


I was under the impression that by introducing generic variance you'd also
get covariant return types for generic interfaces. That is, if a class
implements a member with return type List<Animal> you'd be allowed to
override that and return List<Tiger>. I'd happily start programming around
generic interfaces in my API if I could get covariant return types.

--
With regards
Anders Borum / SphereWorks
Microsoft Certified Professional (.NET MCP)

CSharp/C# >> Generics, Interfaces, and Inheritance question

by Pavel Minaev » Thu, 04 Sep 2008 20:25:33 GMT


Not at all. It means that you'll be able to upcast List<Tiger> to
List<Animal> (and an implicit conversion will be there, too), nothing more.

CSharp/C# >> Generics, Interfaces, and Inheritance question

by Jon Skeet [C# MVP] » Thu, 04 Sep 2008 20:29:40 GMT


Yes, I wouldn't be at all surprised if more details were revealed at
PDC.


For a start that wouldn't work as List<T> is a class, not an interface.
However, there are two separate matters here - declared return type
covariance, and covariant conversions. So consider this method:

public virtual IEnumerable<object> Foo()

You're proposing that you should be able to override that with:
public override IEnumerable<string> Foo() { ... }

I don't believe that will happen for C# 4, but I believe you'll be able
to do:
public override IEnumerable<object> Foo()
{
return new List<string>(); // This wouldn't have worked before
}

--
Jon Skeet - < XXXX@XXXXX.COM >
Web site: http://www.pobox.com/ ~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com

CSharp/C# >> Generics, Interfaces, and Inheritance question

by Jon Skeet [C# MVP] » Thu, 04 Sep 2008 20:49:37 GMT


It doesn't even mean you'll be able to do that, as List<T> is a class,
not an interface.
Furthermore, you wouldn't be able to do it from IList<Tiger> to
IList<Animal> due to the members of IList<T>, e.g. Add, which would
introduce type safety issues.

However, you *could* convert from IEnumerable<Tiger> to
IEnumerable<Animal> as that doesn't introduce any problems - it's a
"read only" interface, as it were.

--
Jon Skeet - < XXXX@XXXXX.COM >
Web site: http://www.pobox.com/ ~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com

Similar Threads

1. Generics: Inheritance and Interface questions

Hi,
I would like to know two things about generics:

1. Can an interface be gerneric? I want the implementing class to be 
generic, so the interface has to be. 

2. I have a gerneric class, which I want to use as a base class for my own. 
But in the subclass I do now the exact type which will be processed and I 
don't want anyone to have the ability of changing this. Is it possible to 
extend a gerneric base class with a non-gerneric class? And if so, how?

Thanks a lot..

Stampede

2. inheritance/polymorphism and maybe generics question - CSharp/C#

3. Generics - Interface Syntax question

Hi group, i need a bit of help with this:

public abstract class BusinessComponent<TData, TDataMapper>
where TData : BusinessEntity,new()
where TDataMapper : DataMappers.DataMapper<TData>, new()

I want BusinessComponent to implement an interface i created, however i
can't get the syntax right! what am i doing wrong? Thanks in advance

Gonzalo

4. Question on interfaces and inheritance - CSharp/C#

5. question on inheritance of interfaces..

  I have interface IAbc,IDef

and  interface  IXyz inherits/implements(what is the right word) IAbc
and IDef


 if  i  reflect the type IXyz it only shows me the members of IXyz and
not IAbc and IDef.

Why?

TIA

6. Generics - A question on generics - delegates - runtime binding. - CSharp/C#

7. Generics - A question on generics - delegates - runtime bindin

Thank you for the reply but I do not think that is the reason. The delegate 
in class A is defined with the signature. It is this signature that should 
match against the methods in class B. And the methods in B do match.

public delegate T GetValueDelegate(A<T> var);

thanks, but I am still missing something.

8. Question about interface inheritance