4

if i have :

   public class A {   public int a1;}
   public class B : A {  public int b1;}

   void myFunc(A a) 
   {}

  static void Main(string[] args)
       {
         B b = new B();
         myFunc(b);
       }

in myFunc , a can access b object but it can reference only (without cast) to a region in memory which is type A.

that is understood.

HOwever in covariance it seems that a can also access b : enter image description here

As you can see - it accepts Enumerable of A and it still can access its B typed objects


questions:

1) Ok, How behind the scenes it is working ? how can an A reference can show me a larger object ?

2) What if i wanted to see in the function the a1 property from the A class ?what should I change ?

edit

covariance related:

Before C# 4, you couldn't pass in List: cannot convert from 'System.Collections.Generic.List' to 'System.Collections.Generic.IEnumerable'

Covariance and contravariance real world example

Community
  • 1
  • 1
Royi Namir
  • 144,742
  • 138
  • 468
  • 792
  • 2
    Nitpick - Pointers in C# are only available in `unsafe` contexts. In .NET we use `reference`. – Oded Feb 03 '12 at 21:46
  • 1
    Indeed, this has nothing to do with covariance... – Thomas Levesque Feb 03 '12 at 21:53
  • @RoyiNamir, indeed you couldn't have written this code without covariance, but this is not relevant for what you're asking. – Thomas Levesque Feb 03 '12 at 22:06
  • @ThomasLevesque the Whole question was started from learning covariance. I met some difficulties of understanding. since covariance let this be possible -passing generic list to Ienumerable - I think it does related. – Royi Namir Feb 03 '12 at 22:08
  • @RoyiNamir, it would be the same if you passed a list of A that contained instances of B, and it would not involve covariance. – Thomas Levesque Feb 03 '12 at 22:15

3 Answers3

6

How can an A reference can show me a larger object?

First off, it is a smaller type. Every giraffe is an animal but not every animal is a giraffe. Therefore there are fewer giraffes in the world than there are animals in the world. Therefore giraffe is a smaller type than animal.

Your type B is a smaller type than A. And of course a reference to a larger type can refer to something of a smaller type.

That has nothing to do with covariance. It is always the case that an IEnumerable<A> can give you a B:

List<A> myList = new List<A>() { new B(); } // No covariance here
Console.WriteLine(myList[0].GetType()); // it's a B.

A list of animals can contain a giraffe. That has nothing to do with covariance.

Similarly, a reference can always give you a smaller type back:

A a = new B(); // Legal!

to those who says it has nothing to do with covariance...

That a sequence of A can contain a B has nothing to do with covariance. What has to do with covariance is that a sequence of B can be converted to a sequence of A by reference conversion. Before covariant conversions were added to C# 4, that conversion would have failed.

What if i wanted to see in the function the a1 property from the A class? what should I change?

You shouldn't change anything; it already works. Try it.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • @RoyiNamir: Of course B is smaller when it extends A. **A variable of type A can contain a B**, and therefore B is *smaller* than A. In the real world a box can only hold things that are *smaller* than the box. You're telling me that a variable can only hold things that are *larger* than itself? That doesn't make any sense. A *subtype* is *smaller* than its *supertype*, just like a *substring* is smaller than the string it comes from, or a *subset* is smaller than its *superset*. Are you saying that the set of giraffes is *larger* than the set of animals because a giraffe is a kind of animal? – Eric Lippert Feb 03 '12 at 22:17
  • If class A has list of 100 items and class B has list of 900 items and B extends A so - the memory for B will be much larger than memory for A.......no? – Royi Namir Feb 03 '12 at 22:20
  • 3
    @RoyiNamir: You are confusing two completely different kinds of size; it's like you're saying that a spider is bigger than a cat because a spider has more legs. Covariance is concerned solely with the size relationship amongst *types*. Of any two types, either one is *bigger* (a supertype) than the other, *smaller* than the other (a subtype) or *not related at all* to the other. A string might be ten million characters, but it is neither bigger nor smaller than a four byte int from the type system's perspective. – Eric Lippert Feb 03 '12 at 22:27
  • Eric, do you feel that using the words 'smaller' and 'bigger' to describe type relationship is very confusing. Why not use subtype and supertype all the time? – SolutionYogi Feb 03 '12 at 22:34
  • @RoyiNamir: Think about it this way. You have a box. The box says "This Box Contains The Name Of An Animal" on it; it does not contain an animal; it contains a piece of paper that names an animal. That piece of paper can name a dog. The number of animals whose names could be written down and put in that box is *larger* than the number of *dogs* whose names could be written down and put in the box. You are asking "Dog is larger than animal, so how can a box that contains the name of an animal have the name of a dog?" That question doesn't make any sense; dog is *smaller* than animal. – Eric Lippert Feb 03 '12 at 22:37
  • 1
    @SolutionYogi: But *subtype* and *supertype* mean "smaller type" and "bigger type" -- that's what "sub" and "super" mean. I don't see the difference. – Eric Lippert Feb 03 '12 at 22:38
  • @RoriNamir: Yes, an **instance** of B does take up more memory than an **instance** of A. So what? Remember, a variable of type B **does not hold a B**. Types that have that property -- that a variable holds the value -- are called **value types**. Types like B are called **reference types**. Every reference is *the same size in memory*. A reference to A is exactly the same size as a reference to B. But none of those sizes are relevant *to the type system*. The type system cares about what the relative sizes of *types* are, not how they are laid out in memory. – Eric Lippert Feb 03 '12 at 22:48
  • 1
    @EricLippert I think I understand you now. you are talking that since `a` can access a much larger of animals types except dog - it is bigger container ( container for many animals except dogs) – Royi Namir Feb 03 '12 at 22:50
  • 1
    @RoyiNamir: **Exactly, yes.** The type system is concerned with answering the question **what can go into this box**. – Eric Lippert Feb 03 '12 at 22:56
  • Well, when I heard the word 'subtype' for the first time, I did not think in terms of 'smaller' or 'bigger', I thought in germs of 'specific' vs 'general'. [See: http://dictionary.reference.com/browse/subtype] I think it was on your blog where I first saw the usage of 'smaller' and 'bigger' to describe type relationship and just like the OP, it confused me. – SolutionYogi Feb 03 '12 at 22:58
  • @Eric thanks Eric, Love you ! you made some people here (in my post )today - smarter ! – Royi Namir Feb 03 '12 at 22:58
  • As someone who did not study computer science proper, my interpretation of 'smaller' and 'bigger' type relates to how I compare other objects as either smaller or bigger. For me, because the derived type has 'more fields', it is bigger and base type is smaller because it has fewer fields. I am sharing my thoughts because you do say that you want to know why people believe the things they do. – SolutionYogi Feb 03 '12 at 23:00
5

As you can see - it accepts Enumerable of A and it still can access its B typed objects

The debugger shows it as a B because it sees that its actual type is B. The code in myFunc can only access the members of A, unless it casts the object to B.

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
0

myFunc sees a type B, because you call it with one in myFunc(b);

YOu see a1 inside the base class A

If you do

static void Main(string[] args)
       {
         A a = new A();
         myFunc(a);
       }

you will see a type A directly

Edit

Just to make that clear:

void myFunc(A a) 

shoud be read as

void myFunc({Either A or something "larger" than A} a) 

with "larger" meaning "inheriting to"

Eugen Rieck
  • 64,175
  • 10
  • 70
  • 92
  • still dont understand why reference from A can show me a larger A (B) – Royi Namir Feb 03 '12 at 21:51
  • In your example, you do NOT pass a reference to an object of type A - you pass a reference to an object of type B (which happens to be based on A): You give a B, you get a B – Eugen Rieck Feb 03 '12 at 21:53
  • This is a bizarre definition of larger. "inheriting from" means **smaller**. "Giraffe" inherits from "Animal", therefore Giraffe is a *smaller* type than Animal. Obviously there are a lot more things in the world that are animals than there are things that are giraffes! A variable of type Animal is **large enough** to hold an instance of the **smaller** type Giraffe; it makes no sense to say that a variable can hold *anything larger than it's type*. – Eric Lippert Feb 03 '12 at 22:12
  • @EricLippert I tried "inheriting to" - sorry, non-english native: What is the correct word for the father->son (a.o.t son->father) in realworld inheritance? – Eugen Rieck Feb 03 '12 at 22:27
  • COncerning "it makes no sense to say that a variable can hold anything larger than it's type" - I beg to diagree: If A extends B extends C, and a function accepts a C, it will also accept a B and an A, both "larger" than C – Eugen Rieck Feb 03 '12 at 22:28
  • No, both types are *smaller* than C, because they both *fit* into a variable of type C. You are welcome to your bizarre definition if it makes you happy, but you should be aware that it is the exact opposite of the generally accepted definition, so you're likely to be misunderstood. – Eric Lippert Feb 03 '12 at 22:30
  • This is how I understood the OQ: He talks of B being larger than A – Eugen Rieck Feb 03 '12 at 22:31
  • Regarding father-son inheritance: I have never understood why people try to explain class inheritance with parent-child metaphors. That metaphor is *completely wrong*. A giraffe is a kind of animal; that does not make animal the "parent" of giraffe; the parent of a giraffe are Mr. & Mrs. Giraffe. **A child is not 'a kind of parent'** and so why should we say that a giraffe is a child of animal just because a giraffe is a kind of animal? Moreover, in language that support both nested types and inheritance, it is confusing: is the supertype or the outer type the parent? – Eric Lippert Feb 03 '12 at 22:32
  • The original poster is getting two completely different kinds of size confused; the type system cares nothing about how much memory a thing consumes. – Eric Lippert Feb 03 '12 at 22:33