6

Consider we have:

abstract class FlyingObject;
case class Rocket(name: String) extends FlyingObject;

what is difference between those two function declarations:

def launch[T <: FlyingObject](fo: T)

and

def launch(fo: FlyingObject)

Great would be some examples when to use which type of declaration...

[UPDATE]

Another great example and explanation can be found there. It's another example of when you should use upper bound instead of just derived class as parameter.

PrimosK
  • 13,848
  • 10
  • 60
  • 78

2 Answers2

7

It might be useful to have a T which is more specific than FlyingObject. Perhaps imagine you have a method

def modifyName(fo: FlyingObject, newName: String): FlyingObject = fo.copy(name=newName)

Which returns a copy of the FlyingObject with a modified name. That makes this code not typecheck:

val newRocket: Rocket = modifyName(oldRocket, "new name")

Since modifyName returns a FlyingObject not a Rocket. instead:

def modifyName[T <: FlyingObject](fo: T, newName: String): T = fo.copy(name=newName)

Will return a Rocket when Rocket is what is passed in.

stew
  • 11,276
  • 36
  • 49
  • In other words, it matter specifically when the return type is type T. – Luigi Plinge Apr 23 '12 at 17:18
  • 2
    @LuigiPlinge: perhaps when its used anywhere else in the type signature. For you might want `def compare[T<:FlyingObject](one: T, two: T)` also – stew Apr 23 '12 at 17:30
4

In addition to @stew answer, an upper bound could be useful when using typeclasses. For instance, suppose you want a method that take two flying objects as well as a collider object defining how to manage collision with other objects. Of course, an asteroid-asteroid collision is not the same as a spaceship-asteroid collision (classical textbook example).

You could write such method as:

def collide[A <: FlyingObject, B <: FlyingObject]
  ( a: A, b: B )( implicit collider: Collider[A,B] ) = collider.apply(a,b)

Then the compiler will provide a correct Collider for you. If instead you wrote:

def collide( a: FlyingObject, b: FlyingObject ) = a.collide(b)

You will have to rely on Obect-Oriented feature to manage the collision which will be really difficult to write and to maintain (double dispatch issue).

paradigmatic
  • 40,153
  • 18
  • 88
  • 147