'v: Ty' in a pattern is not an annotation: Scala ritual

Scala style guides tend to carry more than a few silly and counterproductive suggestions. As such, I limit the kinds of expressions I strongly suggest to those with specific semantic consequences. This sort of “ritual” appears to just be stylish, but turns out to be meaningful in the language.

For example, v: Ty in a pattern is not an annotation. You can easily see this happen, getting an error at runtime for what appears to be a type error here:

def boom(yes: Boolean) = {
  val (s: String, i: Int) = if (yes) (42, "hi") else ("hi", 42)
  s.length + i
}

scala> boom(false)
res0: Int = 44

scala> boom(true)
scala.MatchError: (42,hi) (of class scala.Tuple2)
  at .boom(<console>:12)

It is safer to write nothing at all than to write a type pattern. If I remove : String and : Int, I get a compile-time error for the same code:

scala> def boom(yes: Boolean) = {
         val (s, i) = if (yes) (42, "hi") else ("hi", 42)
         s.length + i
       }
<console>:13: error: value length is not a member of Any
         s.length + i
           ^

This applies to cases, too; there is nowhere in the case syntax for annotations, anything that looks like one is actually a type pattern.

The fix here is to move the types to the part of the val that is actually meant for annotations:

scala> def boom(yes: Boolean) = {
         val (s, i): (String, Int) = if (yes) (42, "hi") else ("hi", 42)
         s.length + i
       }
<console>:12: error: type mismatch;
 found   : Int(42)
 required: String
         val (s, i): (String, Int) = if (yes) (42, "hi") else ("hi", 42)
                                               ^

And now we get the proper error from a proper annotation.

Adapted from an earlier Slack thread; tested with Scala 2.12.11.

6 Likes