Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: strange behavior in `for` pattern matching for None case

Strange behavior in for cycle pattern matching:

scala> val a = Seq(Some(1), None)
a: Seq[Option[Int]] = List(Some(1), None)

scala> for (Some(x) <- a) { println(x) }
1

scala> for (None <- a) { println("none") }
none
none

Why in second example two output 'none' produced? Maybe this example is synthetic and not practical, but such behavior is not expectable. Is this bug or feature?

like image 555
Anton Ermakov Avatar asked Oct 23 '15 09:10

Anton Ermakov


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.

Can we use case classes in pattern matching?

Case classes help us use the power of inheritance to perform pattern matching. The case classes extend a common abstract class. The match expression then evaluates a reference of the abstract class against each pattern expressed by each case class.

Which method of case class allows using objects in pattern matching?

Scala case classes are just regular classes which are immutable by default and decomposable through pattern matching. It uses equal method to compare instance structurally.


2 Answers

What do you know, it is a bug:

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

scala> val vs = Seq(Some(1), None)
vs: Seq[Option[Int]] = List(Some(1), None)

scala> for (n @ None <- vs) println(n)
None

The spec in umambiguous:

http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#for-comprehensions-and-for-loops

Compare midstream assignment, which does not exhibit the bug:

scala> for (v <- vs; None = v) println(v)
scala.MatchError: Some(1) (of class scala.Some)
  at $anonfun$1.apply(<console>:9)
  at $anonfun$1.apply(<console>:9)
  at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
  at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
  at scala.collection.immutable.List.foreach(List.scala:381)
  at scala.collection.TraversableLike$class.map(TraversableLike.scala:245)
  at scala.collection.immutable.List.map(List.scala:285)
  ... 33 elided
like image 172
som-snytt Avatar answered Oct 18 '22 21:10

som-snytt


That's because None was interpreted as a name of variable:

scala> for (None <- a) { println(None) } 
Some(1)
None

Here is simplified example without for:

scala> val None = 5
None: Int = 5

scala> val Some(a) = Some(5)
a: Int = 5
like image 25
dk14 Avatar answered Oct 18 '22 20:10

dk14