Reputation: 63389
For example, Exception.allCatch
is defined as
def allCatch[T]: Catch[T]
Why not just
val allCatch: Catch[Nothing]
when Catch
is covariant in its argument?
Or, why PartialFunction
object defines
def empty[A, B]: PartialFunction[A, B]
instead of just
val empty: PartialFunction[Any,Nothing]
?
Update: So far it seems that the answers miss the point. So please include a specific examples in your answer that really target the question. For example: Show a piece of code that works with def empty[A, B]: PartialFunction[A, B]
but doesn't work (or is less convenient) with val empty: PartialFunction[Any,Nothing]
.
Upvotes: 8
Views: 533
Reputation: 10764
Actually, it seems that Scala standard library has some more places where generic type parameter is redundant (because of type variance). For example, see my question about foreach
. My guess, based on @Peter's answer, is that these redundant generics make the interface more clear. Thanks to them, we don't have to remember which types are covariant, contravariant and invariant. Also, this makes things way simpler for people who are not familiar with variance, which is rather an advanced feature of Scala.
Upvotes: 1
Reputation: 22191
If you hard-code the type, like PartialFunction[Any,Nothing]
, you cannot restrict your function to take a more specific parameter than Any
.
By using a generic type parameter, you can end up with a more flexible satisfying all cases and especially making the function safe.
Let's assume you want a function aiming to take an Animal
as parameter and returning an Integer
.
Let's assume that function is declared as being:
def myFunction: PartialFunction[Any,Nothing]
Firstly, PartialFunction would not be specialized to Animal
at parameter side but to Any
. What about if I pass a Human
as parameter...., it would pass.. What about safety?
Secondly, If this function is declared as returning Nothing
, you can't return from it any value but Nothing
! Indeed, Nothing
subclasses all classes in Scala.
This leads to the known rule that return type parameter must always be covariant in order to make a function interesting, not the case with Nothing
.
In fact, Nothing
is interesting only when dealing with the empty
method of PartialFunction
. Logic since an empty PartialFunction
by definition involves nothing to return and should be forced to do it :)
You would ask: "So why don't we change the return type to Any
?"
Answer: Because you'd lose all the benefit of generic erasure time making compiler to add needed casts automatically => You wouldn't retrieve directly the Integer value, but Any. annoying..
Upvotes: 2
Reputation: 21111
Looking at the source of PartialFunction
available here we can see that it in fact calls a private method on the PartialFunction
object:
private[this] val empty_pf: PartialFunction[Any, Nothing]
So the return type of empty will always be PartialFunction[Any, Nothing]
. As for the reasoning behind I have no idea. Maybe someone else have better insight as to why. You could try the language mailing list as well...
Upvotes: 2
Reputation:
This saves the need for casting later and allows to treat the args type as T instead of Any, which is usually more convenient.
Here is an example:
scala> def func1[T](arg : T) : T = { arg }
func1: [T](arg : T)T
scala> def func2(arg : Any) : Any = { arg }
func2: (arg: Any)Any
scala> func1(4)
res4: Int = 4
scala> func2(4)
res7: Any = 4
Upvotes: 2