## Ex03 Task1: Liskov Principle and precise parameters

burgi
BASIC-Programmierer
Beiträge: 115
Registriert: 15. Apr 2009 18:08
Wohnort: Ludwigshafen

### Ex03 Task1: Liskov Principle and precise parameters

Hi everybody,

I still have some difficulties to fully understand what the given task asks me to do. As far as I understood the Liskov priciple, are there two mayor hints what I should do with my methods concerning their variance.
First, the return parameters of the subclases should be covariant.
Second, the methods arguments (parameters) should be contravariant.

This fits quite well to what Task 1 tells me to do. As for example contravariance of the contains method, and covariance of the add method and a class/ object signature without variance annotations, results in a behaviour like I expect it to have.
So lets have a short example to clarifiy things. There is a class animal, subclasses of animal are, cat and dog, and subclass of dog dogdog, and of cat catcat. Now we take a Tupel[Cat] and fill it with some cats and catcats. With a contravariant contains method, I am allowed to look for cats and catcats, but not for dogs and not for animals, as both do not inherit from cat. If I would add a dog to the Tuple I would receive a Tuple of type Animal, containing cats and dogs. For which I am now allowed to check via contains with cats, catcats, dogs, dogdogs, and animals.

So far for the example. Now such behaviour, which is for my opinion what I (and hopefully Liskov too) intended, is only possible if I declare the baseclass and als subclasses of Tuple to be invariant, which is not what the Task says, but what is seen from compiler side, totally corecct as i have classes which own covariant and contravariant methods, so I should not be allowed to declare them covariant.
So I am a bit confused. At the "Sprechstunde" today with my problem, but unfortunatly I think I missed the essentials, or did not get the point. As I remember Jonathan told me that both methods need to be covariant. For sure if I declare both methods to be covariant, I can declare the whole class to be covariant, but this contradicts with my understanding of the Liskov priciple and as well with the Task, which states to use "precice" method parameters. Covariance for contains leads to the possibility to use it with objects of Any, which should be prevented as I think.

Maybe someone can help me with my problem of understanding things,

Jonnylein
Windoof-User
Beiträge: 30
Registriert: 24. Okt 2007 15:10

### Re: Ex03 Task1: Liskov Principle and precise parameters

'ello!
This fits quite well to what Task 1 tells me to do. As for example contravariance of the contains method, and covariance of the add method and a class/ object signature without variance annotations, results in a behaviour like I expect it to have.
So lets have a short example to clarifiy things. There is a class animal, subclasses of animal are, cat and dog, and subclass of dog dogdog, and of cat catcat. Now we take a Tupel[Cat] and fill it with some cats and catcats. With a contravariant contains method, I am allowed to look for cats and catcats, but not for dogs and not for animals, as both do not inherit from cat. If I would add a dog to the Tuple I would receive a Tuple of type Animal, containing cats and dogs. For which I am now allowed to check via contains with cats, catcats, dogs, dogdogs, and animals.
I think right there is your problem. When you say "contains is a contravariant" method, you have to specify what about it is supposed to be contravariant. The return type is obviously boolean for both Tuple<Cat> and Tuple<Whatever>, so let's have a look at the parameter you are calling contains with.

Code: Alles auswählen

def contains[..type parameter..] (input: T) : Boolean = { .. }
So, your input is of type T and your return is of type Boolean. In your example, you try to look for catcat, which is a subtype of cat, or in scala:

Code: Alles auswählen

[cat >: catcat] // Cat is supertype of Catcat
// or:
[catcat <: cat] // Catcat is subtype of Cat
Which means, if applied to Tuple and your example, it would look something like this:

Code: Alles auswählen

class Animal {..}

class cat extends Animal {..}

class catcat extends cat {..}

trait Tuple[...?{ ...? } 
The concrete implementations for tuples are omitted here, because they are not important to show you the right way.
Alright, so now we have two classes cat and catcat, where cat extends Animal and catcat extends cat.

Since catcat extends cat, Tuple<catcat> should extend Tuple<cat> as well, or to be more concise: Tuple<catcat> is a specialized form of Tuple<cat>.
You already said something really important about method definitions and the Liskov substitution principle:
I still have some difficulties to fully understand what the given task asks me to do. As far as I understood the Liskov priciple, are there two mayor hints what I should do with my methods concerning their variance.
First, the return parameters of the subclases should be covariant.
Second, the methods arguments (parameters) should be contravariant.

Take this information and compare it with the method definition in the piece of code above - I hope I could help you.

As an additional hint: contains(a: Any) should be compileable. That's the reason why the task explicitly asks for a more precise type parameter.

burgi
BASIC-Programmierer
Beiträge: 115
Registriert: 15. Apr 2009 18:08
Wohnort: Ludwigshafen

### Re: Ex03 Task1: Liskov Principle and precise parameters

Hi,

first thanks for the reply. After reading it thoroughly I still have one problem.
My method contains has to be covariant, I got that point now. But the parameter of contains should be contravariant. Thus leading to a signature like:
contains[B >: A](element: A). But this leads to an compiler error telling me that I'm using a covariant Type A in an contravariant position, which is totally convincing as Tuple[+A] is declared to be covariant.
There are two ways to get by with this, one is to declare Tuple[A] to be invariant, which works, but then again I cant use object for Tuple0 or to declare contains' parameter covariant, which leads to the effect that contains accepts Any.

philomat
Erstie
Beiträge: 17
Registriert: 28. Mär 2011 14:50

### Re: Ex03 Task1: Liskov Principle and precise parameters

burgi hat geschrieben: contains[B >: A](element: A).
As I understand it: If you declare the tuple with +A you want to take arguments that can be A, a subclass of A or any super class, but your element is of type A, but it should be B.

burgi
BASIC-Programmierer
Beiträge: 115
Registriert: 15. Apr 2009 18:08
Wohnort: Ludwigshafen

### Re: Ex03 Task1: Liskov Principle and precise parameters

Hi,

thats the point ! If I declare Tuple[+A] (covariant) then all methods and their parameters need to be covariant. But the behaviour which is asked by the Task, is as I see this covariant in adding and contravariant in searching (containing). So I'm confused about the formulation of the Task as it says "use variance annotations", which seems to be not applicable for me.

Greetings DOminic

philomat
Erstie
Beiträge: 17
Registriert: 28. Mär 2011 14:50

### Re: Ex03 Task1: Liskov Principle and precise parameters

I think +A means method parameters should be contravriant and the return types covariant.

burgi
BASIC-Programmierer
Beiträge: 115
Registriert: 15. Apr 2009 18:08
Wohnort: Ludwigshafen

### Re: Ex03 Task1: Liskov Principle and precise parameters

Okay,

maybe I should refine my problem. The question/problem is, if I declare [B >:A]contains(element: B), I can use contains with an instantiation of Object, I'm still not sure if this should be allowed.

philomat
Erstie
Beiträge: 17
Registriert: 28. Mär 2011 14:50

### Re: Ex03 Task1: Liskov Principle and precise parameters

I think it's fine that you can pass an instantiation of Object to the method, I think they dont want us to do it like this : contains(element: Object).