Content-Length: 453845 | pFad | http://github.com/scala/scala/commit/260cea246255bd5eaa14945d7dad07e1cda8ee93

89 Show that @nullOut works as intended · scala/scala@260cea2 · GitHub
Skip to content

Commit 260cea2

Browse files
committed
Show that @nullout works as intended
Needs a restarr to work! The forwarder / alias `IterableOnceOps./:` uses `@nullOut` to clear the `this` reference before calling `foldLeft`. The annotation is also on the method itself to ensure mixin forwarders (generated in the subclass) and the static mixin accessor (generated in the trait) null out the receiver before invoking `/:`. After removing `LazyList.foldLeft`, it inherits the implementation from LinearSeqOps. That method again uses `@nullOut` twice, once to clear `this` when it's no longer needed, and once on the method for the generated accessors. I think we should *not* use `@nullOut` everywhere in the standard library, only on methods that cannot be overridden in LazyList, like `/:`. `@nullOut` works correctly on `mkString` too, but unfortunately the `addString` override in LazyList prevents GC of processed elements due to cycle detection.
1 parent c0322a6 commit 260cea2

File tree

4 files changed

+13
-21
lines changed

4 files changed

+13
-21
lines changed

src/library/scala/collection/IterableOnce.scala

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,8 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
755755
def foldRight[B](z: B)(op: (A, B) => B): B = reversed.foldLeft(z)((b, a) => op(a, b))
756756

757757
@deprecated("Use foldLeft instead of /:", "2.13.0")
758-
@`inline` final def /: [B](z: B)(op: (B, A) => B): B = foldLeft[B](z)(op)
758+
@annotation.nullOut
759+
@`inline` final def /: [B](z: B)(op: (B, A) => B): B = (this: @annotation.nullOut).foldLeft[B](z)(op)
759760

760761
@deprecated("Use foldRight instead of :\\", "2.13.0")
761762
@`inline` final def :\ [B](z: B)(op: (A, B) => B): B = foldRight[B](z)(op)
@@ -1313,9 +1314,10 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
13131314
*
13141315
* @example `List(1, 2, 3).mkString("(", "; ", ")") = "(1; 2; 3)"`
13151316
*/
1317+
@annotation.nullOut
13161318
final def mkString(start: String, sep: String, end: String): String =
13171319
if (knownSize == 0) start + end
1318-
else addString(new StringBuilder(), start, sep, end).result()
1320+
else (this: @annotation.nullOut).addString(new StringBuilder(), start, sep, end).result()
13191321

13201322
/** Displays all elements of this $coll in a string using a separator string.
13211323
*
@@ -1328,7 +1330,8 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
13281330
*
13291331
* @example `List(1, 2, 3).mkString("|") = "1|2|3"`
13301332
*/
1331-
@inline final def mkString(sep: String): String = mkString("", sep, "")
1333+
@annotation.nullOut
1334+
@inline final def mkString(sep: String): String = (this: @annotation.nullOut).mkString("", sep, "")
13321335

13331336
/** Displays all elements of this $coll in a string.
13341337
*
@@ -1339,7 +1342,8 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
13391342
* of all elements of this $coll follow each other without any
13401343
* separator string.
13411344
*/
1342-
@inline final def mkString: String = mkString("")
1345+
@annotation.nullOut
1346+
@inline final def mkString: String = (this: @annotation.nullOut).mkString("")
13431347

13441348
/** Appends all elements of this $coll to a string builder using start, end, and separator strings.
13451349
* The written text begins with the string `start` and ends with the string `end`.
@@ -1365,10 +1369,11 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
13651369
* @param end the ending string.
13661370
* @return the string builder `b` to which elements were appended.
13671371
*/
1372+
@annotation.nullOut
13681373
def addString(b: StringBuilder, start: String, sep: String, end: String): b.type = {
13691374
val jsb = b.underlying
13701375
if (start.length != 0) jsb.append(start)
1371-
val it = iterator
1376+
val it = (this: @annotation.nullOut).iterator
13721377
if (it.hasNext) {
13731378
jsb.append(it.next())
13741379
while (it.hasNext) {

src/library/scala/collection/LinearSeq.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,10 @@ trait LinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with LinearSeq
176176
None
177177
}
178178

179+
@annotation.nullOut
179180
override def foldLeft[B](z: B)(op: (B, A) => B): B = {
180181
var acc = z
181-
var these: LinearSeq[A] = coll
182+
var these: LinearSeq[A] = (this: @annotation.nullOut).coll
182183
while (!these.isEmpty) {
183184
acc = op(acc, these.head)
184185
these = these.tail

src/library/scala/collection/immutable/LazyList.scala

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -416,19 +416,6 @@ final class LazyList[+A] private (lazyState: AnyRef /* EmptyMarker.type | () =>
416416
}
417417
}
418418

419-
/** LazyList specialization of foldLeft which allows GC to collect along the
420-
* way.
421-
*
422-
* @tparam B The type of value being accumulated.
423-
* @param z The initial value seeded into the function `op`.
424-
* @param op The operation to perform on successive elements of the `LazyList`.
425-
* @return The accumulated value from successive applications of `op`.
426-
*/
427-
@tailrec
428-
override def foldLeft[B](z: B)(op: (B, A) => B): B =
429-
if (isEmpty) z
430-
else tail.foldLeft(op(z, head))(op)
431-
432419
// LazyList.Empty doesn't use the SerializationProxy
433420
protected[this] def writeReplace(): AnyRef =
434421
if (knownNonEmpty) new SerializationProxy[A](this) else this

test/junit/scala/collection/immutable/LazyListGCTest.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ class LazyListGCTest {
119119

120120
@Test
121121
def foldLeft(): Unit = {
122-
// fails when using `/:` instead of `foldLeft`
123-
assertLazyListOpAllowsGC((ll, check) => ll.foldLeft(0){ case (s, x) => check(x); s + x}, _ => ())
122+
assertLazyListOpAllowsGC((ll, check) => ll./:(0){ case (s, x) => check(x); s + x}, _ => ())
124123
}
125124
}

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/scala/scala/commit/260cea246255bd5eaa14945d7dad07e1cda8ee93

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy