7

Here is an example:

scala> val xs = List(1,2,3).toIterator.toSeq
xs: Seq[Int] = Stream(1, ?)

A sequence is a materialized collection (it's a List by default), so I expected that toSeq would return a List, not a Stream

The implementation is in TraversableOnce,

  def toSeq: Seq[A] = toStream

why is it not overridden in TraversableLike?

Adrian
  • 3,762
  • 2
  • 31
  • 40
  • 2
    Since it's not necessary to consume the iterator to get a valid `Seq`, why would you? There's always `toList`, `toVector`, etc. if you really want them. – Travis Brown Oct 17 '14 at 19:51
  • 2
    Also, you really should just pretend you don't know that the underlying implementation of the `Seq` you get back is `Stream`. If you care, use a different `toX` method. – Travis Brown Oct 17 '14 at 19:52
  • Travis, you could have the same argument for toIndexedSeq(). IndexedSeq is also a trait, just like Seq. List(1,2,3).toIterator.toIndexedSeq returns a Vector, which is the default implementation of IndexedSeq. I agree that List(1,2,3).toIterator.toSeq returning a List "may" be a bit too specialized, but I guess that keeping the semantics correct would be more important. – Adrian Oct 17 '14 at 20:13
  • 1
    But it's not possible to write a valid `IndexedSeq` implementation that doesn't require consuming the iterator. There's not really any "default implementation" for either `Seq` or `IndexedSeq`—there's the one returned by `apply` on the companion object, but that's not some kind of special status. Also knowledge about which subtype is used is of course not statically available, and it's subject to change. – Travis Brown Oct 17 '14 at 20:26
  • It's also not possible to write a valid Seq implementation that doesn't require consuming the iterator. So why have different semantics for toSeq and toIndexedSeq? On another hand, in our case, iterator.toSeq returns a Stream. Why a Stream? – Adrian Oct 17 '14 at 21:01
  • 1
    But `Stream` _doesn't_ have to consume the iterator, and it's a `Seq`. The contract of `IndexedSeq` requires constant-time access by index, which means we do have to pull all elements out of the iterator. – Travis Brown Oct 17 '14 at 21:09
  • 2
    In any case we're not really talking about the _semantics_ of `toSeq` and `toIndexedSeq`—that's completely captured by their return types. We're talking about implementation details. – Travis Brown Oct 17 '14 at 21:10
  • 1
    Travis, makes sense. I did not realize that Stream is a Seq. Stream is not shown in the scala collection type hierarchy tree images... – Adrian Oct 17 '14 at 21:57

1 Answers1

8

Scala supports infinite iterators, and Stream is the simplest Seq for possible infinite data.

Iterator.from(1).toSeq

terminates (if only a part of the collection is used), but

Iterator.from(1).toList

will never terminate.

You don't want do break code, if an equally valid decision would not. The toSeq method doesn't know the origin of the Iterator, therefor it must assume that it could be infinite.

The Docs "explain" this decision like this:

Converts this traversable or iterator to a sequence. As with toIterable, it's lazy in this default implementation, as this TraversableOnce may be lazy and unevaluated. Note: will not terminate for infinite-sized collections.

http://www.scala-lang.org/api/current/?_ga=1.200291566.1390086478.1406220121#scala.collection.Iterator

Jean Logeart
  • 52,687
  • 11
  • 83
  • 118
bmaderbacher
  • 1,261
  • 1
  • 10
  • 19