471,350 Members | 1,767 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,350 software developers and data experts.

Generics, Interfaces, and Inheritance question

--
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<Tdoes implement the interface, due
to the fact that T must be of typeX (or derived from it)
Aug 21 '08 #1
20 1701
public T GetThing(){return val;}

if you create ABC<TypeYthen 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

Aug 21 '08 #2
--
On Aug 21, 1:40*pm, "Peter Morris" <mrpmorri...@SPAMgmail.comwrote:
* * * public T GetThing(){return val;}

if you create ABC<TypeYthen 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
But typeY is a typeX, so it still fulfills the contract of the
interface.
Aug 21 '08 #3
On Thu, 21 Aug 2008 13:48:41 -0700, -- <on***************@gmail.comwrote:
On Aug 21, 1:40¬*pm, "Peter Morris" <mrpmorri...@SPAMgmail.comwrote:
¬* ¬* ¬* public T GetThing(){return val;}

if you create ABC<TypeYthen 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

But typeY is a typeX, so it still fulfills the contract of the
interface.
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<Twith 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
Aug 21 '08 #4
--
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.

Aug 26 '08 #5
-- <on***************@gmail.comwrote:

<snip>
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.
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 - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Aug 29 '08 #6
On Aug 29, 11:28*pm, Jon Skeet [C# MVP] <sk...@pobox.comwrote:
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.
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.
Aug 31 '08 #7
Hello!
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.
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)

Sep 3 '08 #8
"Anders Borum" <an****@sphereworks.dkwrote in message
news:9B**********************************@microsof t.com...
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.
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.
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".
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...
Sep 4 '08 #9
Hi Pavel,
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.
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)

Sep 4 '08 #10
Anders Borum <an****@sphereworks.dkwrote:
Hi Pavel,
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.

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".
From http://blogs.msdn.com/ericlippert/ar...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 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).
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 - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Sep 4 '08 #11
Hi Jon, et al.

Jon Skeet wrote:
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.
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 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.
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<Animalyou'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)

Sep 4 '08 #12
"Anders Borum" <an****@sphereworks.dkwrote in message
news:CE**********************************@microsof t.com...
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<Animalyou'd be allowed to
override that and return List<Tiger>.
Not at all. It means that you'll be able to upcast List<Tigerto
List<Animal(and an implicit conversion will be there, too), nothing more.
Sep 4 '08 #13
Anders Borum <an****@sphereworks.dkwrote:
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.

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).
Yes, I wouldn't be at all surprised if more details were revealed at
PDC.
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.

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<Animalyou'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.
For a start that wouldn't work as List<Tis 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<objectFoo()

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

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

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Sep 4 '08 #14
Pavel Minaev <in****@gmail.comwrote:
"Anders Borum" <an****@sphereworks.dkwrote in message
news:CE**********************************@microsof t.com...
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<Animalyou'd be allowed to
override that and return List<Tiger>.

Not at all. It means that you'll be able to upcast List<Tigerto
List<Animal(and an implicit conversion will be there, too), nothing more.
It doesn't even mean you'll be able to do that, as List<Tis a class,
not an interface.
Furthermore, you wouldn't be able to do it from IList<Tigerto
IList<Animaldue to the members of IList<T>, e.g. Add, which would
introduce type safety issues.

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

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Sep 4 '08 #15
"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:MP*********************@msnews.microsoft.com. ..
>Not at all. It means that you'll be able to upcast List<Tigerto
List<Animal(and an implicit conversion will be there, too), nothing
more.

It doesn't even mean you'll be able to do that, as List<Tis a class,
not an interface.
Furthermore, you wouldn't be able to do it from IList<Tigerto
IList<Animaldue to the members of IList<T>, e.g. Add, which would
introduce type safety issues.
Yes, I know. Since we didn't actually see the definition of List<T>, I
cheated and assumed that it was a custom interface that could be covariant
:)
However, you *could* convert from IEnumerable<Tigerto
IEnumerable<Animalas that doesn't introduce any problems - it's a
"read only" interface, as it were.
By the way, this is precisely why I think that this form of variance is
almost completely useless in practice. Aside from IEnumerable, I don't see
any other interface, out of collection-related ones in the BCL, that would
benefit from it. Of course, one can refactor the interfaces and split them
into covariant, contravariant, and invariant parts, but this is messy, and I
don't see the BCL guys bothering. I certainly wouldn't. I'd very much prefer
call-site variance such as offered by Java wildcards and "super", but
alas...
Sep 4 '08 #16
Hi Jon,

"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:MP*********************@msnews.microsoft.com. ..
Yes, I wouldn't be at all surprised if more details were revealed at
PDC.
Trust me, I'll be seated in the front row.
For a start that wouldn't work as List<Tis a class, not an interface.
Yes, using List<Twas a bad example; should have been an interface.
public virtual IEnumerable<objectFoo()
You're proposing that you should be able to override that with:
public override IEnumerable<stringFoo() { ... }
That's exactly what I am after. Not just for IEnumerable<Thowever, but for
any interface (I'll take that now that generic classes seem to have been
ruled out of the equation - for some reason). IEnumerable<stringis a
IEnumerable<object>, just like NodeCollection<Pageto NodeCollection<Node>,
having Page inherit from Node.
I don't believe that will happen for C# 4, but I believe you'll be able
to do:
public override IEnumerable<objectFoo()
{
return new List<string>(); // This wouldn't have worked before
}
Well, that's really not a big win because you can do return new
List<string>.Cast<object>(); and stream that way. What's really interesting
was the possibility to actually return a NodeCollection<Pagefor a return
type of NodeCollection<Node>; not just an enumerator. Today we can't return
NodeCollection<Pagefor a return type of NodeCollection<Node>.

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

Sep 4 '08 #17
Pavel Minaev <in****@gmail.comwrote:
It doesn't even mean you'll be able to do that, as List<Tis a class,
not an interface.
Furthermore, you wouldn't be able to do it from IList<Tigerto
IList<Animaldue to the members of IList<T>, e.g. Add, which would
introduce type safety issues.

Yes, I know. Since we didn't actually see the definition of List<T>, I
cheated and assumed that it was a custom interface that could be covariant
:)
<grin>
However, you *could* convert from IEnumerable<Tigerto
IEnumerable<Animalas that doesn't introduce any problems - it's a
"read only" interface, as it were.

By the way, this is precisely why I think that this form of variance is
almost completely useless in practice. Aside from IEnumerable, I don't see
any other interface, out of collection-related ones in the BCL, that would
benefit from it. Of course, one can refactor the interfaces and split them
into covariant, contravariant, and invariant parts, but this is messy, and I
don't see the BCL guys bothering. I certainly wouldn't. I'd very much prefer
call-site variance such as offered by Java wildcards and "super", but
alas...
I can see the delegate stuff being potentially more useful. I
personally find the Java generics variance very hard to understand at
times - and I know I'm not alone in that.

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Sep 4 '08 #18
"Anders Borum" <an****@sphereworks.dkwrote in message
news:%2****************@TK2MSFTNGP04.phx.gbl...
>I don't believe that will happen for C# 4, but I believe you'll be able
to do:
public override IEnumerable<objectFoo()
{
return new List<string>(); // This wouldn't have worked before
}

Well, that's really not a big win because you can do return new
List<string>.Cast<object>(); and stream that way.
You can, and then the method who receives your object can also convert its
type in the same way... but every additional layer of those IEnumerable
wrappers inevitably hits performance. Also, you have to reuse the same
pattern for your own covariant types.
Sep 4 '08 #19
Anders Borum <an****@sphereworks.dkwrote:
public virtual IEnumerable<objectFoo()
You're proposing that you should be able to override that with:
public override IEnumerable<stringFoo() { ... }

That's exactly what I am after. Not just for IEnumerable<Thowever, but for
any interface (I'll take that now that generic classes seem to have been
ruled out of the equation - for some reason). IEnumerable<stringis a
IEnumerable<object>, just like NodeCollection<Pageto NodeCollection<Node>,
having Page inherit from Node.
Only interfaces where it makes sense, however. An IList<stringisn't
an IList<objectfor example.

As Pavel says, it's likely to be used relatively rarely.
I don't believe that will happen for C# 4, but I believe you'll be able
to do:
public override IEnumerable<objectFoo()
{
return new List<string>(); // This wouldn't have worked before
}

Well, that's really not a big win because you can do return new
List<string>.Cast<object>(); and stream that way. What's really interesting
was the possibility to actually return a NodeCollection<Pagefor a return
type of NodeCollection<Node>; not just an enumerator. Today we can't return
NodeCollection<Pagefor a return type of NodeCollection<Node>.
Being able to *actually* return it - for interfaces - will be feasible.
You just won't (necessarily) be able to *declare* that you return it.

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Sep 4 '08 #20
"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:MP*********************@msnews.microsoft.com. ..
I can see the delegate stuff being potentially more useful. I
personally find the Java generics variance very hard to understand at
times - and I know I'm not alone in that.
I've seen such claims before. I think it boils down to this: with C# 4.0
(hopefully) definition-site variance, the burden is on the framework
designers to get it right. If they do, then use is transparent - you declare
methods that take IEnumerable<Base>, and they can magically take
IEnumerable<Derived>. That's wonderful. However, if framework designers
screw it up - e.g. provide you with ICollection<Twhich is neither
covariant not contravariant, because it has both Add() and GetEnumerator()
in a single interface, then there's nothing you can do.

In Java, the situation is reversed. You have to be variance-aware every time
you write code dealing with generics. You have to remember to always type
your arguments as Iterable<? extends T>. But when it comes to more
complicated cases, such as, well, Collection<T>, you can do whatever you
need to be done. If you're only adding elements to collection, you take
Collection<? super T>, and deal with it in a contravariant fashion. If
you're iterating over the collection, you take Collection<? extends T>, and
your code is covariant. If you do both, you just take Collection<T>, and
it's invariant. This allows for flexibility and type-safety throughout the
system, without artificial constraints imposed by someone messing up on the
very top of the chain (such as with ICollection<Tin .NET), but at a cost
of requiring every one along that chain to understand those issues well. As
someone who does, I am obviously in favor of the latter approach - I like
the extra power and extra safety, and don't mind the complexity that comes
with it (and I wouldn't mind effect typing in C# either) ;)
Sep 4 '08 #21

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

21 posts views Thread by Franco Gustavo | last post: by
11 posts views Thread by hammad.awan_nospam | last post: by
7 posts views Thread by JCauble | last post: by
9 posts views Thread by James Crosswell | last post: by
6 posts views Thread by =?Utf-8?B?UXVhbiBOZ3V5ZW4=?= | last post: by
reply views Thread by XIAOLAOHU | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.