parametric types and variance

View: New views
7 Messages — Rating Filter:   Alert me  

parametric types and variance

by Christoph Driessen :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi all,

can anyone explain to me why the following code compiles? As I  
understand it, Aa acts as the lower bound in the implementation of  
classify in class AaClassifier and so I wonder why I'm able to pass in  
a String.

Cheers
Christoph


object Test {
     def main(args: Array[String]) {
         println(new AaClassifier().classify("a"))
     }
}

trait Classifier[+T] {
     def classify[U >: T](t: U): String
}

class AaClassifier extends Classifier[Aa] {
     def classify[T >: Aa](t: T) = t.toString
}

class Aa


Re: parametric types and variance

by Miles Sabin :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Jul 9, 2009 at 3:23 PM, Christoph Drießen<ced@...> wrote:
> can anyone explain to me why the following code compiles? As I understand
> it, Aa acts as the lower bound in the implementation of classify in class
> AaClassifier and so I wonder why I'm able to pass in a String.

You've got your bounds the wrong way around: that's an upper bound, so
T can be instantiated to the supertypes of Aa which are Any, AnyRef
etc.

What I think you want is,

trait Classifier[+T] {
   def classify[U <: T](t: U): String
}

class AaClassifier extends Classifier[Aa] {
   def classify[T <: Aa](t: T) = t.toString
}

Cheers,


Miles

--
Miles Sabin
tel: +44 (0)7813 944 528
skype:  milessabin
http://www.chuusai.com/
http://twitter.com/milessabin

Re: parametric types and variance

by Christoph Driessen :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Miles,
page 396 of Programming in Scala says: " U >: T defines T as the lower  
bound for U". So U must be a supertype of T. In that way you're right  
and that's how I understand it. But how is it possible to pass in a  
String? String isn't a supertype of Aa.

The change you've suggested does not compile:
covariant type T occurs in contravariant position in type >:  
scala.this.Nothing <: T of type U&0
def classify[U <: T](t: U): String

Cheers,
Christoph



Am 09.07.2009 um 16:31 schrieb Miles Sabin:

> On Thu, Jul 9, 2009 at 3:23 PM, Christoph Drießen<ced@...> wrote:
>> can anyone explain to me why the following code compiles? As I  
>> understand
>> it, Aa acts as the lower bound in the implementation of classify in  
>> class
>> AaClassifier and so I wonder why I'm able to pass in a String.
>
> You've got your bounds the wrong way around: that's an upper bound, so
> T can be instantiated to the supertypes of Aa which are Any, AnyRef
> etc.
>
> What I think you want is,
>
> trait Classifier[+T] {
>   def classify[U <: T](t: U): String
> }
>
> class AaClassifier extends Classifier[Aa] {
>   def classify[T <: Aa](t: T) = t.toString
> }
>
> Cheers,
>
>
> Miles
>
> --
> Miles Sabin
> tel: +44 (0)7813 944 528
> skype:  milessabin
> http://www.chuusai.com/
> http://twitter.com/milessabin
>


Re: parametric types and variance

by Christoph Driessen :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Ok, got it! Thanks Miles!

But Classifier also needs to be contravariant it T. I assume you just  
forgot to change + to - Miles, right?

trait Classifier[-T] {
        def classify[U <: T](t: U): String
}


Am 09.07.2009 um 18:20 schrieb Christoph Drießen:

> Hi Miles,
> page 396 of Programming in Scala says: " U >: T defines T as the  
> lower bound for U". So U must be a supertype of T. In that way  
> you're right and that's how I understand it. But how is it possible  
> to pass in a String? String isn't a supertype of Aa.
>
> The change you've suggested does not compile:
> covariant type T occurs in contravariant position in type >:  
> scala.this.Nothing <: T of type U&0
> def classify[U <: T](t: U): String
>
> Cheers,
> Christoph
>
>
>
> Am 09.07.2009 um 16:31 schrieb Miles Sabin:
>
>> On Thu, Jul 9, 2009 at 3:23 PM, Christoph Drießen<ced@...> wrote:
>>> can anyone explain to me why the following code compiles? As I  
>>> understand
>>> it, Aa acts as the lower bound in the implementation of classify  
>>> in class
>>> AaClassifier and so I wonder why I'm able to pass in a String.
>>
>> You've got your bounds the wrong way around: that's an upper bound,  
>> so
>> T can be instantiated to the supertypes of Aa which are Any, AnyRef
>> etc.
>>
>> What I think you want is,
>>
>> trait Classifier[+T] {
>>  def classify[U <: T](t: U): String
>> }
>>
>> class AaClassifier extends Classifier[Aa] {
>>  def classify[T <: Aa](t: T) = t.toString
>> }
>>
>> Cheers,
>>
>>
>> Miles
>>
>> --
>> Miles Sabin
>> tel: +44 (0)7813 944 528
>> skype:  milessabin
>> http://www.chuusai.com/
>> http://twitter.com/milessabin
>>
>


Re: parametric types and variance

by Daniel Sobral :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I recommend reading the Chapter about variance of Programming in Scala.
 
Anyway, notice that what varies is the type ACCEPTED by classify. In this case, classify[AnyRef] is both a supertype of Aa, thus respecting the lower bound, and of String, so a String can be passed to it.
 
If that is confusing, imagine you defined classify to be:
 
 def classify(t: AnyRef) = t.toString
Can you pass a String to such a method? Of course you can, because a String is a subtype of AnyRef. You can pass pretty much anything, except Java primitive types (Scala's AnyVal). Since AnyRef is a supertype of AA, then this is a valid definition for classify.
On Thu, Jul 9, 2009 at 1:20 PM, Christoph Drießen <ced@...> wrote:
Hi Miles,
page 396 of Programming in Scala says: " U >: T defines T as the lower bound for U". So U must be a supertype of T. In that way you're right and that's how I understand it. But how is it possible to pass in a String? String isn't a supertype of Aa.

The change you've suggested does not compile:
covariant type T occurs in contravariant position in type >: scala.this.Nothing <: T of type U&0

def classify[U <: T](t: U): String

Cheers,
Christoph



Am 09.07.2009 um 16:31 schrieb Miles Sabin:


On Thu, Jul 9, 2009 at 3:23 PM, Christoph Drießen<ced@...> wrote:
can anyone explain to me why the following code compiles? As I understand
it, Aa acts as the lower bound in the implementation of classify in class
AaClassifier and so I wonder why I'm able to pass in a String.

You've got your bounds the wrong way around: that's an upper bound, so
T can be instantiated to the supertypes of Aa which are Any, AnyRef
etc.

What I think you want is,

trait Classifier[+T] {
 def classify[U <: T](t: U): String
}

class AaClassifier extends Classifier[Aa] {
 def classify[T <: Aa](t: T) = t.toString
}

Cheers,


Miles

--
Miles Sabin
tel: +44 (0)7813 944 528
skype:  milessabin
http://www.chuusai.com/
http://twitter.com/milessabin





--
Daniel C. Sobral

Something I learned in academia: there are three kinds of academic reviews: review by name, review by reference and review by value.

Re: parametric types and variance

by Paul Phillips-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Jul 09, 2009 at 04:23:40PM +0200, Christoph Drießen wrote:
> can anyone explain to me why the following code compiles? As I
> understand it, Aa acts as the lower bound in the implementation of
> classify in class AaClassifier and so I wonder why I'm able to pass in
> a String.

Because you're not passing a String, you're passing an AnyRef (which
happens to be a String.)

--
Paul Phillips      | One way is to make it so simple that there are
Moral Alien        | obviously no deficiencies. And the other way is to make
Empiricist         | it so complicated that there are no obvious deficiencies.
up hill, pi pals!  |     -- Hoare

Parent Message unknown Re: parametric types and variance

by Miles Sabin :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Jul 9, 2009 at 5:37 PM, Christoph Drießen<ced@...> wrote:
> Ok, got it! Thanks Miles!
>
> But Classifier also needs to be contravariant it T. I assume you just forgot
> to change + to - Miles, right?
>
> trait Classifier[-T] {
>  def classify[U <: T](t: U): String
> }

Oops ... yes, quite right.

Cheers,


Miles

--
Miles Sabin
tel: +44 (0)7813 944 528
skype:  milessabin
http://www.chuusai.com/
http://twitter.com/milessabin