Skip to content

Commit d527842

Browse files
authored
Merge pull request #5 from scala/iterable-once
Make it clearer that the `iterator` method will return a fresh Iterator at each call
2 parents 75c20ad + e857b3f commit d527842

File tree

4 files changed

+58
-60
lines changed

4 files changed

+58
-60
lines changed

src/main/scala/strawman/collection/CollectionStrawman6.scala

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import Predef.{augmentString => _, wrapString => _, _}
44
import scala.reflect.ClassTag
55
import annotation.unchecked.uncheckedVariance
66
import annotation.tailrec
7+
import scala.language.higherKinds
78

89
/* ------------ Base Traits -------------------------------- */
910

1011
/** Iterator can be used only once */
1112
trait IterableOnce[+A] {
12-
def iterator: Iterator[A]
13+
def iterator(): Iterator[A]
1314
}
1415

1516
/** Base trait for instances that can construct a collection from an iterable */
@@ -50,14 +51,14 @@ trait LinearSeq[+A] extends Seq[A] with LinearSeqLike[A, LinearSeq] { self =>
5051
def tail: LinearSeq[A]
5152

5253
/** `iterator` is overridden in terms of `head` and `tail` */
53-
def iterator = new Iterator[A] {
54+
def iterator() = new Iterator[A] {
5455
private[this] var current: Seq[A] = self
5556
def hasNext = !current.isEmpty
56-
def next = { val r = current.head; current = current.tail; r }
57+
def next() = { val r = current.head; current = current.tail; r }
5758
}
5859

5960
/** `length` is defined in terms of `iterator` */
60-
def length: Int = iterator.length
61+
def length: Int = iterator().length
6162

6263
/** `apply` is defined in terms of `drop`, which is in turn defined in
6364
* terms of `tail`.
@@ -78,8 +79,8 @@ trait IndexedSeq[+A] extends Seq[A] { self =>
7879
}
7980

8081
/** Base trait for strict collections that can be built using a builder.
81-
* @param A the element type of the collection
82-
* @param Repr the type of the underlying collection
82+
* @tparam A the element type of the collection
83+
* @tparam Repr the type of the underlying collection
8384
*/
8485
trait Buildable[+A, +Repr] extends Any with IterableMonoTransforms[A, Repr] {
8586

@@ -89,7 +90,7 @@ trait Buildable[+A, +Repr] extends Any with IterableMonoTransforms[A, Repr] {
8990
/** Optimized, push-based version of `partition`. */
9091
override def partition(p: A => Boolean): (Repr, Repr) = {
9192
val l, r = newBuilder
92-
coll.iterator.foreach(x => (if (p(x)) l else r) += x)
93+
coll.iterator().foreach(x => (if (p(x)) l else r) += x)
9394
(l.result, r.result)
9495
}
9596

@@ -108,7 +109,7 @@ trait Builder[-A, +To] { self =>
108109

109110
/** Bulk append. Can be overridden if specialized implementations are available. */
110111
def ++=(xs: IterableOnce[A]): this.type = {
111-
xs.iterator.foreach(+=)
112+
xs.iterator().foreach(+=)
112113
this
113114
}
114115

@@ -177,25 +178,25 @@ trait LinearSeqLike[+A, +C[X] <: LinearSeq[X]] extends SeqLike[A, C] {
177178
*/
178179
trait IterableOps[+A] extends Any {
179180
protected def coll: Iterable[A]
180-
private def iterator = coll.iterator
181+
private def iterator() = coll.iterator()
181182

182183
/** Apply `f` to each element for tis side effects */
183-
def foreach(f: A => Unit): Unit = iterator.foreach(f)
184+
def foreach(f: A => Unit): Unit = iterator().foreach(f)
184185

185186
/** Fold left */
186-
def foldLeft[B](z: B)(op: (B, A) => B): B = iterator.foldLeft(z)(op)
187+
def foldLeft[B](z: B)(op: (B, A) => B): B = iterator().foldLeft(z)(op)
187188

188189
/** Fold right */
189-
def foldRight[B](z: B)(op: (A, B) => B): B = iterator.foldRight(z)(op)
190+
def foldRight[B](z: B)(op: (A, B) => B): B = iterator().foldRight(z)(op)
190191

191192
/** The index of the first element in this collection for which `p` holds. */
192-
def indexWhere(p: A => Boolean): Int = iterator.indexWhere(p)
193+
def indexWhere(p: A => Boolean): Int = iterator().indexWhere(p)
193194

194195
/** Is the collection empty? */
195-
def isEmpty: Boolean = !iterator.hasNext
196+
def isEmpty: Boolean = !iterator().hasNext
196197

197198
/** The first element of the collection. */
198-
def head: A = iterator.next()
199+
def head: A = iterator().next()
199200

200201
/** The number of elements in this collection, if it can be cheaply computed,
201202
* -1 otherwise. Cheaply usually means: Not requiring a collection traversal.
@@ -205,10 +206,10 @@ trait IterableOps[+A] extends Any {
205206
/** The number of elements in this collection. Does not terminate for
206207
* infinite collections.
207208
*/
208-
def size: Int = if (knownSize >= 0) knownSize else iterator.length
209+
def size: Int = if (knownSize >= 0) knownSize else iterator().length
209210

210211
/** A view representing the elements of this collection. */
211-
def view: View[A] = View.fromIterator(iterator)
212+
def view: View[A] = View.fromIterator(iterator())
212213

213214
/** Given a collection factory `fi` for collections of type constructor `C`,
214215
* convert this collection to one of type `C[A]`. Example uses:
@@ -229,7 +230,7 @@ trait IterableOps[+A] extends Any {
229230
/** Copy all elements of this collection to array `xs`, starting at `start`. */
230231
def copyToArray[B >: A](xs: Array[B], start: Int = 0): xs.type = {
231232
var i = start
232-
val it = iterator
233+
val it = iterator()
233234
while (it.hasNext) {
234235
xs(i) = it.next()
235236
i += 1
@@ -320,7 +321,7 @@ trait SeqMonoTransforms[+A, +Repr] extends Any with IterableMonoTransforms[A, Re
320321
case v: IndexedView[A] => fromIterableWithSameElemType(v.reverse)
321322
case _ =>
322323
var xs: List[A] = Nil
323-
var it = coll.iterator
324+
var it = coll.iterator()
324325
while (it.hasNext) xs = it.next() :: xs
325326
fromIterableWithSameElemType(xs)
326327
}
@@ -386,7 +387,7 @@ extends Seq[A]
386387
private var aliased = false
387388
private var len = 0
388389

389-
def iterator = first.iterator
390+
def iterator() = first.iterator()
390391

391392
def fromIterable[B](coll: Iterable[B]) = ListBuffer.fromIterable(coll)
392393

@@ -451,7 +452,7 @@ extends Seq[A]
451452

452453
override def view = new ArrayBufferView(elems, start, end)
453454

454-
def iterator = view.iterator
455+
def iterator() = view.iterator()
455456

456457
def fromIterable[B](it: Iterable[B]): ArrayBuffer[B] =
457458
ArrayBuffer.fromIterable(it)
@@ -506,7 +507,7 @@ object ArrayBuffer extends IterableFactory[ArrayBuffer] {
506507
def fromIterable[B](coll: Iterable[B]): ArrayBuffer[B] =
507508
if (coll.knownSize >= 0) {
508509
val elems = new Array[AnyRef](coll.knownSize)
509-
val it = coll.iterator
510+
val it = coll.iterator()
510511
for (i <- 0 until elems.length) elems(i) = it.next().asInstanceOf[AnyRef]
511512
new ArrayBuffer[B](elems, elems.length)
512513
}
@@ -563,7 +564,7 @@ object LazyList extends IterableFactory[LazyList] {
563564

564565
def fromIterable[B](coll: Iterable[B]): LazyList[B] = coll match {
565566
case coll: LazyList[B] => coll
566-
case _ => fromIterator(coll.iterator)
567+
case _ => fromIterator(coll.iterator())
567568
}
568569

569570
def fromIterator[B](it: Iterator[B]): LazyList[B] =
@@ -600,12 +601,11 @@ case class ArrayView[A](xs: Array[A]) extends IndexedView[A] {
600601
/* ---------- Iterators ---------------------------------------------------*/
601602

602603
/** A core Iterator class */
603-
trait Iterator[+A] extends IterableOnce[A] { self =>
604+
trait Iterator[+A] { self =>
604605
def hasNext: Boolean
605606
def next(): A
606-
def iterator = this
607607
def foldLeft[B](z: B)(op: (B, A) => B): B =
608-
if (hasNext) foldLeft(op(z, next))(op) else z
608+
if (hasNext) foldLeft(op(z, next()))(op) else z
609609
def foldRight[B](z: B)(op: (A, B) => B): B =
610610
if (hasNext) op(next(), foldRight(z)(op)) else z
611611
def foreach(f: A => Unit): Unit =
@@ -652,7 +652,7 @@ trait Iterator[+A] extends IterableOnce[A] { self =>
652652
private var myCurrent: Iterator[B] = Iterator.empty
653653
private def current = {
654654
while (!myCurrent.hasNext && self.hasNext)
655-
myCurrent = f(self.next()).iterator
655+
myCurrent = f(self.next()).iterator()
656656
myCurrent
657657
}
658658
def hasNext = current.hasNext
@@ -663,7 +663,7 @@ trait Iterator[+A] extends IterableOnce[A] { self =>
663663
private var first = true
664664
private def current = {
665665
if (!myCurrent.hasNext && first) {
666-
myCurrent = xs.iterator
666+
myCurrent = xs.iterator()
667667
first = false
668668
}
669669
myCurrent
@@ -674,7 +674,7 @@ trait Iterator[+A] extends IterableOnce[A] { self =>
674674
def take(n: Int): Iterator[A] = new Iterator[A] {
675675
private var i = 0
676676
def hasNext = self.hasNext && i < n
677-
def next =
677+
def next() =
678678
if (hasNext) {
679679
i += 1
680680
self.next()
@@ -690,7 +690,7 @@ trait Iterator[+A] extends IterableOnce[A] { self =>
690690
this
691691
}
692692
def zip[B](that: IterableOnce[B]): Iterator[(A, B)] = new Iterator[(A, B)] {
693-
val thatIterator = that.iterator
693+
val thatIterator = that.iterator()
694694
def hasNext = self.hasNext && thatIterator.hasNext
695695
def next() = (self.next(), thatIterator.next())
696696
}
@@ -699,10 +699,10 @@ trait Iterator[+A] extends IterableOnce[A] { self =>
699699
object Iterator {
700700
val empty: Iterator[Nothing] = new Iterator[Nothing] {
701701
def hasNext = false
702-
def next = throw new NoSuchElementException("next on empty iterator")
702+
def next() = throw new NoSuchElementException("next on empty iterator")
703703
}
704704
def apply[A](xs: A*): Iterator[A] = new IndexedView[A] {
705705
val length = xs.length
706706
def apply(n: Int) = xs(n)
707-
}.iterator
707+
}.iterator()
708708
}

src/main/scala/strawman/collection/View.scala

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,36 @@ trait View[+A] extends Iterable[A] with IterableLike[A, View] {
1212
/** Avoid copying if source collection is already a view. */
1313
override def fromIterable[B](c: Iterable[B]): View[B] = c match {
1414
case c: View[B] => c
15-
case _ => View.fromIterator(c.iterator)
15+
case _ => View.fromIterator(c.iterator())
1616
}
1717
override def className = "View"
1818
}
1919

2020
/** This object reifies operations on views as case classes */
2121
object View {
2222
def fromIterator[A](it: => Iterator[A]): View[A] = new View[A] {
23-
def iterator = it
23+
def iterator() = it
2424
}
2525

2626
/** The empty view */
2727
case object Empty extends View[Nothing] {
28-
def iterator = Iterator.empty
28+
def iterator() = Iterator.empty
2929
override def knownSize = 0
3030
}
3131

3232
/** A view with given elements */
3333
case class Elems[A](xs: A*) extends View[A] {
34-
def iterator = Iterator(xs: _*)
34+
def iterator() = Iterator(xs: _*)
3535
override def knownSize = xs.length // should be: xs.knownSize, but A*'s are not sequences in this strawman.
3636
}
3737

3838
/** A view that filters an underlying collection. */
39-
case class Filter[A](val underlying: Iterable[A], p: A => Boolean) extends View[A] {
40-
def iterator = underlying.iterator.filter(p)
39+
case class Filter[A](underlying: Iterable[A], p: A => Boolean) extends View[A] {
40+
def iterator() = underlying.iterator().filter(p)
4141
}
4242

4343
/** A view that partitions an underlying collection into two views */
44-
case class Partition[A](val underlying: Iterable[A], p: A => Boolean) {
44+
case class Partition[A](underlying: Iterable[A], p: A => Boolean) {
4545

4646
/** The view consisting of all elements of the underlying collection
4747
* that satisfy `p`.
@@ -56,41 +56,41 @@ object View {
5656

5757
/** A view representing one half of a partition. */
5858
case class Partitioned[A](partition: Partition[A], cond: Boolean) extends View[A] {
59-
def iterator = partition.underlying.iterator.filter(x => partition.p(x) == cond)
59+
def iterator() = partition.underlying.iterator().filter(x => partition.p(x) == cond)
6060
}
6161

6262
/** A view that drops leading elements of the underlying collection. */
6363
case class Drop[A](underlying: Iterable[A], n: Int) extends View[A] {
64-
def iterator = underlying.iterator.drop(n)
64+
def iterator() = underlying.iterator().drop(n)
6565
protected val normN = n max 0
6666
override def knownSize =
6767
if (underlying.knownSize >= 0) (underlying.knownSize - normN) max 0 else -1
6868
}
6969

7070
/** A view that takes leading elements of the underlying collection. */
7171
case class Take[A](underlying: Iterable[A], n: Int) extends View[A] {
72-
def iterator = underlying.iterator.take(n)
72+
def iterator() = underlying.iterator().take(n)
7373
protected val normN = n max 0
7474
override def knownSize =
7575
if (underlying.knownSize >= 0) underlying.knownSize min normN else -1
7676
}
7777

7878
/** A view that maps elements of the underlying collection. */
7979
case class Map[A, B](underlying: Iterable[A], f: A => B) extends View[B] {
80-
def iterator = underlying.iterator.map(f)
80+
def iterator() = underlying.iterator().map(f)
8181
override def knownSize = underlying.knownSize
8282
}
8383

8484
/** A view that flatmaps elements of the underlying collection. */
8585
case class FlatMap[A, B](underlying: Iterable[A], f: A => IterableOnce[B]) extends View[B] {
86-
def iterator = underlying.iterator.flatMap(f)
86+
def iterator() = underlying.iterator().flatMap(f)
8787
}
8888

8989
/** A view that concatenates elements of the underlying collection with the elements
9090
* of another collection or iterator.
9191
*/
9292
case class Concat[A](underlying: Iterable[A], other: IterableOnce[A]) extends View[A] {
93-
def iterator = underlying.iterator ++ other
93+
def iterator() = underlying.iterator() ++ other
9494
override def knownSize = other match {
9595
case other: Iterable[_] if underlying.knownSize >= 0 && other.knownSize >= 0 =>
9696
underlying.knownSize + other.knownSize
@@ -103,20 +103,18 @@ object View {
103103
* of another collection or iterator.
104104
*/
105105
case class Zip[A, B](underlying: Iterable[A], other: IterableOnce[B]) extends View[(A, B)] {
106-
def iterator = underlying.iterator.zip(other)
106+
def iterator() = underlying.iterator().zip(other)
107107
override def knownSize = other match {
108-
case other: Iterable[_] if underlying.knownSize >= 0 && other.knownSize >= 0 =>
109-
underlying.knownSize min other.knownSize
110-
case _ =>
111-
-1
108+
case other: Iterable[_] => underlying.knownSize min other.knownSize
109+
case _ => -1
112110
}
113111
}
114112
}
115113

116114
/** View defined in terms of indexing a range */
117115
trait IndexedView[+A] extends View[A] with ArrayLike[A] { self =>
118116

119-
def iterator: Iterator[A] = new Iterator[A] {
117+
def iterator(): Iterator[A] = new Iterator[A] {
120118
private var current = 0
121119
def hasNext = current < self.length
122120
def next: A = {
@@ -136,21 +134,21 @@ object IndexedView {
136134

137135
class Take[A](underlying: IndexedView[A], n: Int)
138136
extends View.Take(underlying, n) with IndexedView[A] {
139-
override def iterator = super.iterator // needed to avoid "conflicting overrides" error
137+
override def iterator() = super.iterator() // needed to avoid "conflicting overrides" error
140138
def length = underlying.length min normN
141139
def apply(i: Int) = underlying.apply(i)
142140
}
143141

144142
class Drop[A](underlying: IndexedView[A], n: Int)
145143
extends View.Take(underlying, n) with IndexedView[A] {
146-
override def iterator = super.iterator
144+
override def iterator() = super.iterator()
147145
def length = (underlying.length - normN) max 0
148146
def apply(i: Int) = underlying.apply(i + normN)
149147
}
150148

151149
class Map[A, B](underlying: IndexedView[A], f: A => B)
152150
extends View.Map(underlying, f) with IndexedView[B] {
153-
override def iterator = super.iterator
151+
override def iterator() = super.iterator()
154152
def length = underlying.length
155153
def apply(n: Int) = f(underlying.apply(n))
156154
}

src/main/scala/strawman/collection/package.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ package object collection extends LowPriority {
9393
with ArrayLike[Char] {
9494

9595
protected def coll = new StringView(s)
96-
def iterator = coll.iterator
96+
def iterator() = coll.iterator()
9797

9898
protected def fromIterableWithSameElemType(coll: Iterable[Char]): String = {
9999
val sb = new StringBuilder
@@ -135,7 +135,7 @@ package object collection extends LowPriority {
135135
*/
136136
def ++(xs: IterableOnce[Char]): String = {
137137
val sb = new StringBuilder() ++= s
138-
for (ch <- xs.iterator) sb += ch
138+
for (ch <- xs.iterator()) sb += ch
139139
sb.result
140140
}
141141

@@ -152,7 +152,7 @@ package object collection extends LowPriority {
152152
with ArrayLike[A] {
153153

154154
protected def coll = new ArrayView(xs)
155-
def iterator = coll.iterator
155+
def iterator() = coll.iterator()
156156

157157
def length = xs.length
158158
def apply(i: Int) = xs.apply(i)

0 commit comments

Comments
 (0)