Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type capture in Scala case statements

Tags:

scala

Consider the following piece of Scala code:

type i = Integer
val s1: List[Any] = List(1, "two")
s1 collect { case e: i => e } foreach (e => println(s"$e, ${e.getClass}"))

val s2: List[List[Any]] = List(List(1, "two"), List("one", 2))
s2 collect { case e: List[i] => e } foreach (e => println(s"$e, ${e.getClass}"))

val s3: List[List[Any]] = List(List(1, "two"), List("one", 2))
s3 collect { case e: List[`i`] => e } foreach (e => println(s"$e, ${e.getClass}"))

s1 filters on i so it only prints the elements of type i, in our case Integer:

1, class java.lang.Integer

s2 defines a new type variable called i (which shadows the original i) and assigns to it the current type of e. It matches all the elements in s2, so it outputs:

List(1, two), class scala.collection.immutable.$colon$colon
List(one, 2), class scala.collection.immutable.$colon$colon

s3 tries to only filter on elements of type List[Integer], since it treats i as a stable identifier, but because of erasure, this ends up returning the whole list:

List(1, two), class scala.collection.immutable.$colon$colon
List(one, 2), class scala.collection.immutable.$colon$colon

Now, what I don't understand is why treat i differently in the s1 and s2 cases. In one situation it refers to the already defined type variable, but in the other situation, it creates a new type variable.

like image 926
Henry Henrinson Avatar asked Jan 02 '26 00:01

Henry Henrinson


1 Answers

It's type erasure, and nothing to do with the i alias, or the stability thereof

(incidentally, you really shouldn't use lower case type names like this!)

If you substitute the alias and run in a REPL with the -unchecked flag, you get:

val s3: List[List[Any]] = List(List(1, "two"), List("one", 2))
s3: List[List[Any]] = List(List(1, two), List(one, 2))

s3 collect { case e: List[Integer] => e } foreach (e => println(s"$e, ${e.getClass}"))

<console>:9: warning: non-variable type argument Integer in type pattern List[Integer] is unchecked since it is eliminated by erasure
  s3 collect { case e: List[Integer] => e } foreach (e => println(s"$e,${e.getClass}"))
                       ^
List(1, two), class scala.collection.immutable.$colon$colon
List(one, 2), class scala.collection.immutable.$colon$colon
like image 82
Kevin Wright Avatar answered Jan 03 '26 13:01

Kevin Wright



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!