I'm learning Scala by working the exercises from the book "Scala for the Impatient". One question asks:
Given a mutable
Pair[S, T]
class, use a type constraint to define a swap method that can be called if the type parameters are the same.
My code:
class Pair[T, S](var first: T, var second: S) {
def swap(implicit ev: T =:= S) {
val temp = first
first = second // doesn't compile
second = temp
}
}
The code above fails to compile with the complaint that first
and second
are different types. Well, I just nicely told the compiler that they're not. How can I tell it to shut up?
You've just told the compiler that types passed to your class as
T
andS
should be equal - you just require an evidence of their equality, which can be used to infer actualT
andS
correctly when you pass actual types (but not inside generic class itself). It doesn't mean thatT
andS
are interchangable. Btw, it doesn't change anything but you did a mistake by defining newS
andT
, should be:However it's still doesn't compile. Why? Just think of it:
So what is return type compiler should infer?
List[T]
orList[S]
. the only it can do isList[Any]
. So having same and different types simulteniously has no sense. If you want different names - just usetype S = T
no evidence will be needed.And what is the real case of having
S
andT
different in constructor and same in some method. It's simply logically incorrect (when talking about abstract types - not concrete substitutions).Btw,
=:=
is not the compiler feature - there is no special processing for that in compiler. The whole implementation is it inside scalaPredef
:So it's just
tpEquals[A]
implicit which takes typeA
and gives youA =:= A
- when you requireT =:= U
it's trying to make such conversion which is possible only for equal types. And the process of checking implicit itself actually happens only when you pass actualT
andU
, not when you defining them.About your particular problem:
Or just (as @m-z and @Imm suggested):
T =:= S
extendsT => S
and this implicitly added function (even as an object) is interpreted as implicit conversion fromT
toS
in Scala, so it works like both types are equal, which is pretty cool.