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?
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.
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.
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.
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.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With