From 12e35774a52f209a822161417e6ff06ebac047bd Mon Sep 17 00:00:00 2001 From: NthPortal Date: Thu, 14 May 2020 01:31:46 -0400 Subject: [PATCH] Increase laziness of #:: for LazyList Change `#::` for `LazyList` so that the tail computation is wrapped as a state computation for a new `LazyList`, thus deferring its execution as long as possible. --- .../scala/collection/immutable/LazyList.scala | 2 +- .../immutable/LazyListLazinessTest.scala | 36 ++++++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/library/scala/collection/immutable/LazyList.scala b/src/library/scala/collection/immutable/LazyList.scala index 6c4cb2fc5b60..9b0f966a72fe 100644 --- a/src/library/scala/collection/immutable/LazyList.scala +++ b/src/library/scala/collection/immutable/LazyList.scala @@ -1117,7 +1117,7 @@ object LazyList extends SeqFactory[LazyList] { /** Construct a LazyList consisting of a given first element followed by elements * from another LazyList. */ - def #:: [B >: A](elem: => B): LazyList[B] = newLL(sCons(elem, l())) + def #:: [B >: A](elem: => B): LazyList[B] = newLL(sCons(elem, newLL(l().state))) /** Construct a LazyList consisting of the concatenation of the given LazyList and * another LazyList. */ diff --git a/test/junit/scala/collection/immutable/LazyListLazinessTest.scala b/test/junit/scala/collection/immutable/LazyListLazinessTest.scala index 5e0f398bc85b..e610b25809bf 100644 --- a/test/junit/scala/collection/immutable/LazyListLazinessTest.scala +++ b/test/junit/scala/collection/immutable/LazyListLazinessTest.scala @@ -205,7 +205,7 @@ class LazyListLazinessTest { } @Test - def lazyAppendedAll_appendedAll_properlyLazy(): Unit = { + def lazyAppendedAll_properlyLazy(): Unit = { genericAppendedColl_properlyLazy(_ lazyAppendedAll _) } @@ -748,7 +748,7 @@ class LazyListLazinessTest { @Test def `#:: properlyLazy`(): Unit = { - val factory = lazyListFactory { init => + val headInitFactory = lazyListFactory { init => def gen(index: Int): LazyList[Int] = { def elem(): Int = { init.evaluate(index); index } if (index >= LazinessChecker.count) LazyList.empty @@ -757,12 +757,25 @@ class LazyListLazinessTest { gen(0) } - assertRepeatedlyLazy(factory) + assertRepeatedlyLazy(headInitFactory) + + val tailInitFactory = lazyListFactory { init => + def gen(index: Int): LazyList[Int] = { + if (index >= LazinessChecker.count) LazyList.empty + else { + init.evaluate(index) + index #:: gen(index + 1) + } + } + + LazyList.empty lazyAppendedAll gen(0) // prevent initial state evaluation + } + assertRepeatedlyLazy(tailInitFactory) } @Test def `#::: properlyLazy`(): Unit = { - val factory = lazyListFactory { init => + val headInitFactory = lazyListFactory { init => def gen(index: Int): LazyList[Int] = { def elem(): LazyList[Int] = LazyList.fill(1) { init.evaluate(index); index } if (index >= LazinessChecker.count) LazyList.empty @@ -771,7 +784,20 @@ class LazyListLazinessTest { gen(0) } - assertRepeatedlyLazy(factory) + assertRepeatedlyLazy(headInitFactory) + + val tailInitFactory = lazyListFactory { init => + def gen(index: Int): LazyList[Int] = { + if (index >= LazinessChecker.count) LazyList.empty + else { + init.evaluate(index) + LazyList.fill(1)(index) #::: gen(index + 1) + } + } + + LazyList.empty lazyAppendedAll gen(0) // prevent initial state evaluation + } + assertRepeatedlyLazy(tailInitFactory) } @Test