covariance and contravariance

T

Tony Johansson

Hi!

Here is some text from e learning.
"Covariance specifies that the return type of the invoked method must
inherit from the return type of the delegate and contravariance specifies
that the type of each parameter in the delegate must inherit from the type
of the parameter in the invoked method."

What I find funny is the following.
1. If you will use Covariance then the return type of the method must be
derived from the return type of the delegete.
So here we consider the returntype of the delegate as more general then the
returntype of the method. I mean I can see the delegete as a template.
2. If you will use contravariance then we look at the parameter. It would
have been logical if we would have consider the parameter type of the
delegate as more general then the parameter of the method. I mean it would
have followed the same pattern as the covariance. The strange thing is that
it's the other way around. The parameter of the method is consider as more
general then the parameter of the delegete. Very unlogical ??

Here one example of covariance where the return type Dog is derived from
Mammal
class Mammal {}
class Dog : Mammal{}
class Program
{
public delegate Mammal HandlerMethod();
public static Mammal FirstHandler()
{ return null;

public static Dog SecondHandler()
{return null;}

static void Main()
{
HandlerMethod handler1 = new HandlerMethod(FirstHandler);
HandlerMethod handler2 = new HandlerMethod(SecondHandler);
}
}

Here one example of contravaraince where the parameter Dog in the delegete
is derived from Mammal
class Mammal {}
class Dog : Mammal{}
class Program
{
public delegate void HandlerMethod(Dog sampleDog);
public static void FirstHandler(Mammal elephant)
{
}
public static void SecondHandler(Dog sheepDog)
{
}
static void Main(string[] args)
{
HandlerMethod handler1 = FirstHandler;
HandlerMethod handler2 = SecondHandler;
}
}


So my question is why have they not followed the same pattern between
covariance and contravariance so it would be more easy to know where the
type that is more general is located.

//Tony
 
H

Harlan Messinger

Tony said:
Hi!

Here is some text from e learning.
"Covariance specifies that the return type of the invoked method must
inherit from the return type of the delegate and contravariance specifies
that the type of each parameter in the delegate must inherit from the type
of the parameter in the invoked method."

What I find funny is the following.
1. If you will use Covariance then the return type of the method must be
derived from the return type of the delegete.
So here we consider the returntype of the delegate as more general then the
returntype of the method. I mean I can see the delegete as a template.
2. If you will use contravariance then we look at the parameter. It would
have been logical if we would have consider the parameter type of the
delegate as more general then the parameter of the method. I mean it would
have followed the same pattern as the covariance. The strange thing is that
it's the other way around. The parameter of the method is consider as more
general then the parameter of the delegete. Very unlogical ??

Logical and necessary.

Suppose you have

public delegate Type1 MyDelegate(Type2 param);

and a method

public TypeA MyMethod(TypeB param) { ... }

and the following code that uses these:

public MyDelegate myDelegate = new MyDelegate(MyMethod);
Type1 result;
Type2 x = new Type2(...);
result = myDelegate(x);

In order to work, MyMethod has to be guaranteed to be able to accept x
as an argument. For this to be true, TypeB has to be Type2, or else it
has to be a *base* type of Type2.

On the other hand, what the method returns has to be something that can
fit into a result of Type1, which means that TypeA has to be Type1, or
else it has to be a *derived* type of Type1.

To put it more concisely: the constraints on the method are that it:

1. *must* accept *every* argument that *can* be *provided to* the delegate

2. *mustn't* return *any* result that *can't* be *returned by* the delegate.

These constraints work in opposite directions.
 
T

Tony Johansson

Harlan Messinger said:
Logical and necessary.

Suppose you have

public delegate Type1 MyDelegate(Type2 param);

and a method

public TypeA MyMethod(TypeB param) { ... }

and the following code that uses these:

public MyDelegate myDelegate = new MyDelegate(MyMethod);
Type1 result;
Type2 x = new Type2(...);
result = myDelegate(x);

In order to work, MyMethod has to be guaranteed to be able to accept x as
an argument. For this to be true, TypeB has to be Type2, or else it has to
be a *base* type of Type2.

On the other hand, what the method returns has to be something that can
fit into a result of Type1, which means that TypeA has to be Type1, or
else it has to be a *derived* type of Type1.

To put it more concisely: the constraints on the method are that it:

1. *must* accept *every* argument that *can* be *provided to* the delegate

2. *mustn't* return *any* result that *can't* be *returned by* the
delegate.

These constraints work in opposite directions.

I still don't understand why it's not possible to have the parameter of the
delegate as the more general as it is when using the covariance.

//Tony
 
H

Harlan Messinger

Tony said:
I still don't understand why it's not possible to have the parameter of the
delegate as the more general as it is when using the covariance.
If a delegate says, "You can call me with ANY ARGUMENT that is a
Person", and you were able to set up the delegate to call a method that
only accepts a Doctor argument, then what do you expect would happen
when someone calls the delegate with a BusDriver argument?
 
T

Tony Johansson

Harlan Messinger said:
If a delegate says, "You can call me with ANY ARGUMENT that is a Person",
and you were able to set up the delegate to call a method that only
accepts a Doctor argument, then what do you expect would happen when
someone calls the delegate with a BusDriver argument?

Now I understand why it must work as it does.
Your last mail was good to easy understand this.

//Tony
 
A

Arne Vajhøj

Here is some text from e learning.
"Covariance specifies that the return type of the invoked method must
inherit from the return type of the delegate and contravariance specifies
that the type of each parameter in the delegate must inherit from the type
of the parameter in the invoked method."

What I find funny is the following.
1. If you will use Covariance then the return type of the method must be
derived from the return type of the delegete.
So here we consider the returntype of the delegate as more general then the
returntype of the method. I mean I can see the delegete as a template.
2. If you will use contravariance then we look at the parameter. It would
have been logical if we would have consider the parameter type of the
delegate as more general then the parameter of the method. I mean it would
have followed the same pattern as the covariance. The strange thing is that
it's the other way around. The parameter of the method is consider as more
general then the parameter of the delegete. Very unlogical ??

Here one example of covariance where the return type Dog is derived from
Mammal
class Mammal {}
class Dog : Mammal{}
class Program
{
public delegate Mammal HandlerMethod();
public static Mammal FirstHandler()
{ return null;

public static Dog SecondHandler()
{return null;}

static void Main()
{
HandlerMethod handler1 = new HandlerMethod(FirstHandler);
HandlerMethod handler2 = new HandlerMethod(SecondHandler);
}
}

Here one example of contravaraince where the parameter Dog in the delegete
is derived from Mammal
class Mammal {}
class Dog : Mammal{}
class Program
{
public delegate void HandlerMethod(Dog sampleDog);
public static void FirstHandler(Mammal elephant)
{
}
public static void SecondHandler(Dog sheepDog)
{
}
static void Main(string[] args)
{
HandlerMethod handler1 = FirstHandler;
HandlerMethod handler2 = SecondHandler;
}
}


So my question is why have they not followed the same pattern between
covariance and contravariance so it would be more easy to know where the
type that is more general is located.

Did you see the code example I posted yesterday in the
"delegate signature" thread ?

Arne
 
T

Tony Johansson

Arne Vajhøj said:
Here is some text from e learning.
"Covariance specifies that the return type of the invoked method must
inherit from the return type of the delegate and contravariance specifies
that the type of each parameter in the delegate must inherit from the
type
of the parameter in the invoked method."

What I find funny is the following.
1. If you will use Covariance then the return type of the method must be
derived from the return type of the delegete.
So here we consider the returntype of the delegate as more general then
the
returntype of the method. I mean I can see the delegete as a template.
2. If you will use contravariance then we look at the parameter. It would
have been logical if we would have consider the parameter type of the
delegate as more general then the parameter of the method. I mean it
would
have followed the same pattern as the covariance. The strange thing is
that
it's the other way around. The parameter of the method is consider as
more
general then the parameter of the delegete. Very unlogical ??

Here one example of covariance where the return type Dog is derived from
Mammal
class Mammal {}
class Dog : Mammal{}
class Program
{
public delegate Mammal HandlerMethod();
public static Mammal FirstHandler()
{ return null;

public static Dog SecondHandler()
{return null;}

static void Main()
{
HandlerMethod handler1 = new HandlerMethod(FirstHandler);
HandlerMethod handler2 = new HandlerMethod(SecondHandler);
}
}

Here one example of contravaraince where the parameter Dog in the
delegete
is derived from Mammal
class Mammal {}
class Dog : Mammal{}
class Program
{
public delegate void HandlerMethod(Dog sampleDog);
public static void FirstHandler(Mammal elephant)
{
}
public static void SecondHandler(Dog sheepDog)
{
}
static void Main(string[] args)
{
HandlerMethod handler1 = FirstHandler;
HandlerMethod handler2 = SecondHandler;
}
}


So my question is why have they not followed the same pattern between
covariance and contravariance so it would be more easy to know where the
type that is more general is located.

Did you see the code example I posted yesterday in the
"delegate signature" thread ?

Arne

Yes!!

//Tony
 
A

Arne Vajhøj

Arne Vajhøj said:
Here is some text from e learning.
"Covariance specifies that the return type of the invoked method must
inherit from the return type of the delegate and contravariance specifies
that the type of each parameter in the delegate must inherit from the
type
of the parameter in the invoked method."

What I find funny is the following.
1. If you will use Covariance then the return type of the method must be
derived from the return type of the delegete.
So here we consider the returntype of the delegate as more general then
the
returntype of the method. I mean I can see the delegete as a template.
2. If you will use contravariance then we look at the parameter. It would
have been logical if we would have consider the parameter type of the
delegate as more general then the parameter of the method. I mean it
would
have followed the same pattern as the covariance. The strange thing is
that
it's the other way around. The parameter of the method is consider as
more
general then the parameter of the delegete. Very unlogical ??

Here one example of covariance where the return type Dog is derived from
Mammal
class Mammal {}
class Dog : Mammal{}
class Program
{
public delegate Mammal HandlerMethod();
public static Mammal FirstHandler()
{ return null;

public static Dog SecondHandler()
{return null;}

static void Main()
{
HandlerMethod handler1 = new HandlerMethod(FirstHandler);
HandlerMethod handler2 = new HandlerMethod(SecondHandler);
}
}

Here one example of contravaraince where the parameter Dog in the
delegete
is derived from Mammal
class Mammal {}
class Dog : Mammal{}
class Program
{
public delegate void HandlerMethod(Dog sampleDog);
public static void FirstHandler(Mammal elephant)
{
}
public static void SecondHandler(Dog sheepDog)
{
}
static void Main(string[] args)
{
HandlerMethod handler1 = FirstHandler;
HandlerMethod handler2 = SecondHandler;
}
}


So my question is why have they not followed the same pattern between
covariance and contravariance so it would be more easy to know where the
type that is more general is located.

Did you see the code example I posted yesterday in the
"delegate signature" thread ?

Yes!!

It should illustrate why "in" types are the way they are
(and easily converted to explain why "out" types are the
way they are).

Just look at actual call being done and see if it makes
sense or not.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top