scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

Lazier val definitions with pattern matching #7141

Closed scabug closed 1 year ago

scabug commented 11 years ago

Miles Sabin stumbled upon an interesting corner case in how lazy val definitions interact with pattern matching. The basic idea:

scala> val stream = Stream.iterate(0, 3) { x => println(x); x + 1 }
stream: scala.collection.immutable.Stream[Int] = Stream(0, ?)

scala> lazy val Stream(a, b, c) = stream
a: Int = <lazy>
b: Int = <lazy>
c: Int = <lazy>

scala> a
0
1
res0: Int = 0

One would hope that only a is forced, but all three values are. This is because of how the val definition is expanded:

lazy val $fresh = stream match {
  case Stream(a, b, c) => (a, b, c)
}
lazy val a = $fresh._1
lazy val b = $fresh._2
lazy val c = $fresh._3

The culprit is construction of a tuple in the synthesized case clause: tuples are strict, so forcing a forces the whole tuple.

If the language spec instead required an expansion similar to:

lazy val a = stream match { case Stream(a, _, _) => a }
lazy val b = stream match { case Stream(_, b, _) => b }
lazy val c = stream match { case Stream(_, _, c) => c }

Or if the library had LazyTuple types:

lazy val $fresh = stream match {
  case Stream(a, b, c) => LazyTuple3(a, b, c)
}
lazy val a = $fresh._1
lazy val b = $fresh._2
lazy val c = $fresh._3

... then the laziness would be appropriately deferred to Stream.

That being said, I don't actually know how one would write an appropriate Stream.unapplySeq, or unapply for any data type in general, that doesn't force all value members. Seems like a separate unapplyLazy, returning an Option[LazyTuple], would be necessary... and that's horrible.

scabug commented 11 years ago

Imported From: https://issues.scala-lang.org/browse/SI-7141?orig=1 Reporter: Dan Rosen (mergeconflict)

SethTisue commented 1 year ago

interesting, but more of a language design discussion, and surely out of scope for Scala 2 anyway