Sunday, May 17, 2009

Polymorphism, why do you fail me?

Polymorphism, it's the cornerstone of object oriented programming. We couldn't live without it. So then, tell me why this rather trivial case fails to compile.

public class B : A { }

public void Foo (ref A bar) { }

public void Baz ()
{
B b = new B ();
Foo (ref b);
}


The issue is hat you can't pass a 'B' parameter type by ref where a 'ref A' is expected. Why is this? What case could possibly fail if this was allowed?

12 comments:

Anonymous said...

public void Foo (ref A bar)
{
bar = new A();
}

If you call Foo with an B-Instance, it's like:
B b = new A();
And that is no allowed?!
I'm not sure, maybe I'm talking bullshit. :|

Ed said...

I think the anonymous poster there has it right. You could conceivably assign a base class to a derived class pointer. Such way lies madness and exceptions and ow.

Alan said...

Hah, that's a very good point. Now why did neither of us think of that before I blogged the question!

Anonymous said...

Try this:

B b = new B();
A a = (A)b;
Foo(ref a);

Should work.

Zaiden said...

I guess that the problem is because the compiler is treating ref types as invariant types, instead of covariant as you - and we all - want.

But I'm just guessing here...

jonmpryor said...

The point to ref and out is that the called method can change the object reference, as the first anonymous poster pointed out was possible.

The ramifications, though:

// C is a sibling to B
class C : A {}

public void Bar(ref A bar)
{
b = new C();
// should be valid, as C is a
// subclass of A.
}

thus allowing the bizarro (and invalid):

public void Qux()
{
B b = new B();
Bar (ref b);
}

If the above were possible, a 'B' instance variable would in fact be referencing a type that cannot be a 'B' -- a 'C'!

This is, of course, bad.

It is for similar reasons that (without covariant/contravariant support) an IEnumerable[string] isn't implicitly convertable to an IEnumerable[object], and an IList[string] will never be implicitly convertable to an IList[object].

Zaiden said...

Basically, the same reason behind the invariant types on 2.0 Generics.

Great explanation jonmpryor!

Anonymous said...

public void Baz ()
{
B b = new B ();
Foo (ref b);
}

This wont work as Foo() requires an A-type. But as B is a child of A you can try:

public void Baz ()
{
A b = new B ();
Foo (ref b);
}

This will work and you don't need any casts

Raja R Harinath said...
This comment has been removed by the author.
Raja R Harinath said...

* A normal (in) parameter allows arguments from subclasses, but more importantly, disallows superclass arguments

* A return "parameter" allows assignment to "arguments" from superclasses, but more importantly, disallows assignment to subclass "arguments"

* An out parameter is like a return value, and theoretically (not in C#) can accept arguments from superclasses

* A ref parameter is in/out and thus allows neither subclasses nor superclasses

So, your question could've been: why doesn't C# allow superclasses in out parameters?

* firstly, it introduces complications in the overload resolution mechanism for relatively low benefit

* secondly, there's no way to distinguish, in a type-safe manner, between ref and out parameters at the CIL level. Yes, you can attach an [Out] attribute, but this doesn't enforce type-safety.

gaohui said...

Have you noticed ed hardy Clothing that she is spending time with ed hardy sale one person in particular ed hardy and they seemed to come from ed hardy UK nowhere. When you ask how she ed hardy cheap knows them she becomes aloof and ed hardy Clothes disinterested. Is there someone's house ed hardy store she seems to be always going to? This edhardy.com could spell something is wrong with the christian audigier sale relationship. Is she taking trips, possibly day ed hardy dresses trips or small vacations without you? If ed hardy Polos she was doing this before you even ed hardy sandals got married or dated, then it may be okay, but if it is a recent ed hardy Jackets development then you may have problems.

sports handicapping services said...

Fantastic post.I like your article.Very informative post.

Hit Counter