Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top