Function arguments: upper bound vs parent class as argument?
Asked Answered
D

2

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.

Diplegia answered 23/4, 2012 at 16:49 Comment(0)
M
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.

Maddox answered 23/4, 2012 at 16:57 Comment(2)
In other words, it matter specifically when the return type is type T.Bobbiebobbin
@LuigiPlinge: perhaps when its used anywhere else in the type signature. For you might want def compare[T<:FlyingObject](one: T, two: T) alsoMaddox
P
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).

Philosophism answered 23/4, 2012 at 17:40 Comment(1)
Great addition to the answer of @stew.. +1Diplegia

© 2022 - 2024 — McMap. All rights reserved.