You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Miles Sabin stumbled upon an interesting corner case in how lazy val definitions interact with pattern matching. The basic idea:
scala>valstream=Stream.iterate(0, 3) { x => println(x); x +1 }
stream: scala.collection.immutable.Stream[Int] =Stream(0, ?)
scala>lazyvalStream(a, b, c) = stream
a:Int= <lazy>
b:Int= <lazy>
c:Int= <lazy>
scala> a
01
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:
lazyval$fresh= stream match {
caseStream(a, b, c) => (a, b, c)
}
lazyvala= $fresh._1
lazyvalb= $fresh._2
lazyvalc= $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:
lazyvala= stream match { caseStream(a, _, _) => a }
lazyvalb= stream match { caseStream(_, b, _) => b }
lazyvalc= stream match { caseStream(_, _, c) => c }
Or if the library had LazyTuple types:
lazyval$fresh= stream match {
caseStream(a, b, c) =>LazyTuple3(a, b, c)
}
lazyvala= $fresh._1
lazyvalb= $fresh._2
lazyvalc= $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.
The text was updated successfully, but these errors were encountered:
Miles Sabin stumbled upon an interesting corner case in how
lazy val
definitions interact with pattern matching. The basic idea:One would hope that only
a
is forced, but all three values are. This is because of how the val definition is expanded:The culprit is construction of a tuple in the synthesized
case
clause: tuples are strict, so forcinga
forces the whole tuple.If the language spec instead required an expansion similar to:
Or if the library had
LazyTuple
types:... 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
, orunapply
for any data type in general, that doesn't force all value members. Seems like a separateunapplyLazy
, returning anOption[LazyTuple]
, would be necessary... and that's horrible.The text was updated successfully, but these errors were encountered: