Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala pattern matching and type inference

Could someone explain why the following code compiles?

Option("foo") match {
  case x: List[String] => println("A")
  case _ => println("B")
}

This gives me an (expected) warning about type erasure, but it still compiles. I expected this to throw a type error, like it does if I matched on "foo" instead of Option("foo").

Thanks!

like image 721
sidnair09 Avatar asked Sep 09 '12 19:09

sidnair09


People also ask

Does Scala have pattern matching?

Pattern matching is the second most widely used feature of Scala, after function values and closures. Scala provides great support for pattern matching, in processing the messages. A pattern match includes a sequence of alternatives, each starting with the keyword case.

How does Scala pattern matching work?

Pattern matching is a mechanism for checking a value against a pattern. A successful match can also deconstruct a value into its constituent parts. It is a more powerful version of the switch statement in Java and it can likewise be used in place of a series of if/else statements.

How pattern matching works in a function's parameter list?

Pattern matching tests whether a given value (or sequence of values) has the shape defined by a pattern, and, if it does, binds the variables in the pattern to the corresponding components of the value (or sequence of values). The same variable name may not be bound more than once in a pattern.

What is pattern matching explain with example?

Pattern matching is the process of checking whether a specific sequence of characters/tokens/data exists among the given data. Regular programming languages make use of regular expressions (regex) for pattern matching.


2 Answers

The code is commented, so let's take a moment to savor that:

  /** If we can absolutely rule out a match we can fail early.
   *  This is the case if the scrutinee has no unresolved type arguments
   *  and is a "final type", meaning final + invariant in all type parameters.
   */

Notice that None is not final, for instance. I know, right?

If you ever try scalac -Ypatmat-debug, the comment here might help:

https://github.com/scala/scala/pull/650

Reachability is almost within reach:

https://issues.scala-lang.org/browse/SI-6146

But I don't see any promises about what might someday be warnable. For performance reasons? One could also say, why should it warn about an instanceOf[Foo[_]]?

For now, the spec sections 8.2 - 8.4 motivate why matching against Foo[a] is interesting (because of the bounds a acquires). I think I'll go read that again. After some coffee.

trait Foo[+A]
final class Fuzz[+A] extends Foo[A]
final object Fooz extends Foo[Nothing]
object Futz extends Foo[Nothing]

//error
Fooz match {
  case x: List[_] => println("A")
  case _ => println("B")
}
//no error
Futz match { ... }
like image 50
som-snytt Avatar answered Sep 26 '22 02:09

som-snytt


I would assume that the compiler is treating both Option and List as Product, which is why it compiles. As you say, the warning about type erasure is expected. Here's an example that uses another Product:

scala> Option("foo") match {
 | case x: Tuple2[String,String] => println("TUPLE")
 | case x: List[String] => println("LIST")
 | case _ => println("OTHER")
 | }
<console>:9: warning: non variable type-argument String in type pattern (String, String)       is unchecked since it is eliminated by erasure
          case x: Tuple2[String,String] => println("TUPLE")
                  ^
<console>:10: warning: non variable type-argument String in type pattern List[String] is unchecked since it is eliminated by erasure
          case x: List[String] => println("LIST")
                  ^

UPDATE w/r/t case classes (because of the comment below):

scala> case class Foo(bar: Int)
defined class Foo

scala> val y: Product = Foo(123)
y: Product = Foo(123)
like image 45
timothy Avatar answered Sep 25 '22 02:09

timothy