Reputation: 801
Following trait declares 2 functions: f1 and f2
trait Test[+T] {
def f1[U >: T](a: U): Boolean
def f2[U](a: U): Boolean
}
Are they same? If not, what is is a difference?
Upvotes: 2
Views: 154
Reputation: 18424
I think they are the same, in terms of behavior. Both functions need to be implemented for any type. But types are just as much about giving the compiler more information to help you prevent bugs and such, and I can think of some strange corner cases where one might be preferable to the other. For example:
class Foo
class Bar extends Foo
object BarChecker extends Test[Foo] {
def f1[U >: Foo](u: U): Boolean = {
if (u.isInstanceOf[Bar]) {
true
} else {
throw new RuntimeException("fail!")
}
}
def f2[U](u: U): Boolean = {
if (u.isInstanceOf[Bar]) {
true
} else {
throw new RuntimeException("fail!")
}
}
}
val x = BarChecker.f1[Foo](_) // can't do BarChecker.f1[Bar](_)
x(new Bar) // true
x(new Foo) // runtime exception
val y = BarChecker.f2[Bar](_)
y(new Bar) // true
y(new Foo) // compile error
Of course you could fix this with:
val x: Bar => Boolean = BarChecker.f1[Foo](_)
But my point is different type signatures can have different effects on which errors are possible or likely to be made when using them.
Upvotes: 1
Reputation: 3055
In term of execution, yes they are same. Both take parameter of type U, and return result of type Boolean. However, in term of type parameter, they are not. Method f1
have a lower bound type parameter however method f2
don't.
So, what does that mean?
In case of method f2
, you can provide any type parameter. In case of method f1
, you can only provide type parameter which is equal to type T
or which is superType
of T
. For example:
class Foo1(name:String)
class Foo2(name:String) extends Foo1(name)
class Foo3(name:String) extends Foo2(name)
class Test[+T] {
def f1[U >: T](a: U): Boolean = true
def f2[U](a: U): Boolean = true
}
val obj: Test[Foo2] = new Test[Foo2]
val foo1: Foo1 = new Foo1("1")
val foo2: Foo2 = new Foo2("2")
val foo3: Foo3 = new Foo3("3")
//F2 execute on any type you provide.
testInstance.f2[Foo1](foo1)
testInstance.f2[Foo2](foo2)
testInstance.f2[Foo3](foo3)
testInstance.f1[Foo2](foo2) //Foo2 is equal to type T.
testInstance.f1[Foo1](foo1) //Foo1 is supertype of T - Foo2.
testInstance.f1[Foo3](foo3) //Does not compile, because Foo3 is not superType of T - Foo2.
In fact, in Scala, in case of Co-variance annotation [+T], you must define an lower bound. Following will fail:
class Test[+T] {
def f1(a: T): Boolean = true //This will fail.
def f2[U](a: U): Boolean = true
}
Upvotes: 1