3
votes

Assume the following declarations made into the Scala repl:

class Animal
class Bird extends Animal
class Chicken extends Bird
type SubType = t forSome { type t <: Bird }
type SuperType = t forSome { type t >: Bird }

As I expect, SubType is of a type that conforms to Bird. Since Animal is a superclass of Bird, a variable of type SubType cannot hold value of type Animal:

scala> val foo: SubType = new Animal
<console>:10: error: type mismatch;
 found   : Animal
 required: SubType
       val foo: SubType = new Animal

and yet this corollary is not as I expect:

scala> val foo: SuperType = new Chicken
foo: SuperType = Chicken@1fea8dbd

The assignment succeeds, and so do these:

scala> val foo: SuperType = 2
foo: SuperType = 2

scala> val foo: SuperType = "wtf?"
foo: SuperType = wtf?

scala>

Again, here's SuperType:

type SuperType = t forSome { type t >: Bird }

According to SLS 4.3,

A type declaration type t [tps ] >: L <: U declares t to be an abstract type with lower bound type L and upper bound type U.

So I'm declaring t to be an abstract type with lower bound Bird. Chicken is not a superclass of Bird, neither are String nor Int.

I thought that maybe it's because a Chicken is an Any and a SuperType can store an Any. But if I change the declaration of SuperType to this:

type SuperType = t forSome { type t >: Bird <: Animal}

to set an upper bound of Animal nothing seems to change.

Questions

First

How are my assignments of values of types Chicken Int and String to a SuperType variable allowed by existential clauses { type t >: Bird } and { type t >: Bird <: Animal}?

Second

What is the significance of the word "abstract" in the quoted specification that "A type declaration type t [tps ] >: L <: U declares t to be an abstract type..." What would the difference in meaning be if the word "abstract' were not there?

1

1 Answers

1
votes

I think the confusion is between the use of the term "bound" and "constraint". The "<:" and ">:" syntax constructs are for specifying type constraints, not bounds. When you say

{ type t >: Bird } 

you are merely constraining the type "t" such that inhabitants of that type must share a superclass with Bird. Since Chicken and Bird both extend Animal, the constraint is met, and Scala allows the assignment. This is also why your "bogus" assignments work (String and Int both share the superclass Any with Bird. The later constraint you proposed

{ type t >: Bird <: Animal } 

properly restricts your examples of String and Int, as there exists no type in the type hierarchy of String or Int that meets the constraint of being a supertype of Bird while also being a subtype of Animal. However, that will still allow your initial assignment.

Edit: Other answers on SO say that both are called bounds. Shows how much I know. :)