Why aren't reference types polymorphic?

Why aren't reference types polymorphic?

Rate This
  • Comments 35

Q: Why aren't reference types polymorphic?

A: Consider the following code:

using System;
class Dog {
   public string Name;
}

class Test
{
   public static void Swap(ref object a, ref object b) {
      object temp;
      temp = a;
      a = b;
      b = temp;
   } public static void Main() { Dog d1 = new Dog(); d1.Name = "fido"; Dog d2 = new Dog(); d2.Name = "rex"; Swap(ref d1, ref d2); } }


The compiler will report an error on the call to the Swap() function. Why? Consider if the swap function was like this:

   public static void Swap(ref object a, ref object b) {

a = 5;

b = “Hello“;

   }

If the compiler allowed this code, it would mean assigning a boxed int to a Dog object, which is clearly not type safe.

[Author: Eric Gunnerson]

Leave a Comment
  • Please add 5 and 5 and type the answer here:
  • Post
  • And, the simple solution is generics:

    public static void Swap<T>(ref T a, ref T b)
    {
    T temp a;
    a = b;
    b = temp;
    }
  • Ok - I still don't get this. Why does this still compile? a and b are still called by reference, right?
    [code]
    public static void Swap2(object a, object b)
    {
    object temp;
    temp = a;
    a = b;
    b = temp;
    }
    [/code]
    and
    [code]Swap2(d1, d2);[/code]
  • Without ref, d1 and d2 aren't modified by the call to Swap2. You'll see that they didn't actually get swapped. In the a=5, b="hello" case, you just change those local variables and d1 and d2 are left pointing to the dog objects.
  • Oskar,
    Your example compiles but doesn't actually perform a swap.

    --
    I think the terminology of this stuff is very confusing. There are reference types and there are value types. There is pass by value and pass by reference. Pass by reference is completely orthogonal to a reference type. So, I don't think the title is correct, because you are talking about pass by reference as opposed to reference types in general.

    Perhaps something like: "Why is there no implicit base class conversion when a reference is passed by reference to a method?"

    Clear as mud?
  • Agreed, the title is confusing.

    For more discussion of parameter passing, see

    http://www.pobox.com/~skeet/csharp/parameters.html
  • Jon,

    Thanks for a very enlightening article. I was one of the many (surely) who confused reference types and reference parameters. I now understand what Dan and Johan mean - of course they are correct.

    Again, thank you.
  • In .NET, objects are passed by value, by default, so without the "ref", there is no reference passed.
  • that is like saying why arent apples oranges
  • Ernst: No, without the "ref" a reference *is* passed if the parameter is a reference type - but the reference is passed *by* value.
  • This is meaningless. Why can't I code a general method, have it compile and let it fail at runtime if that is what I want? My usage of swap will always pass two references of the same type. The code looks correct to me. Why do I always have to type cast or create a strongly typed anything?
  • Because some of us rather like working in a strongly typed environment.

    If you don't, use VB.NET with Option Strict Off.
  • Ok. So why aren't output parameters polymorphic. Of course, instead of passing in argument that derives from the formal parameter, you would have to do the reverse: The formal parameter would have to derive from the argument.

    public class C {
    public void Copy(StreamReader a, out StreamReader b) {b = a;}
    public void WhyNot() {
    StreamReader a = new StreamReader(...);
    TextReader b;
    Copy(a, out b); // Won't compile, but could.
    }
    }
  • If I modify the swap function as:
    Dog tmp = a;
    a.Name = b.Name;
    b.Name = tmp.Name;
    the the swap will not give the correct value;
    How is this differ from:
    Dog temp= a;
    a = b;
    b = temp;
  • Ray: Output parameters possibly could be covariant as described, but I think most people would find that fairly confusing.

    Ben: Your swap differs entirely, because in the first version a and tmp are references to the same object - so when you've done a.Name = b.Name, you no longer have a reference to the original a.Name - assigning b.Name = tmp.Name is redundant. That's part of how references work, and nothing to do with reference parameters.
Page 1 of 3 (35 items) 123