-
Notifications
You must be signed in to change notification settings - Fork 72
Don’t force views elements prematurely. #343
Conversation
IndexedView[A] was previously trying to return an IndexedView[A] on transformation operations such as filter or take. Doing so sometimes required to evaluate a views elements to build an indexed sequence from which to get an IndexedView. Now IndexedView[A] returns only a View[A] on such operations.
Doesn't this change clobber the performance of |
Yes. |
Well, maybe it doesn't because |
Well to be more precise: |
I think there's a big difference between non-indexable and indexable operations. |
oh sorry we were talking about |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks correct. I think this was the intention all the time. We already have the overrides of IndexedView
methods to return an IndexedView
where appropriate.
@@ -294,19 +294,7 @@ trait ArrayLike[+A] extends Any { | |||
} | |||
|
|||
/** View defined in terms of indexing a range */ | |||
trait IndexedView[+A] extends View[A] with ArrayLike[A] with SeqOps[A, View, IndexedView[A]] { self => | |||
|
|||
final override def toSeq: immutable.Seq[A] = to(immutable.IndexedSeq) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should consider making this the default for Iterable.toSeq
and build something like an ArrayBuffer
. If you care about linear characteristics for consing / unconsing you have to request an appropriate type, otherwise you get the most efficient representation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
most efficient representation for what?
Building a List
is faster than building a Vector
, IIRC.
IndexedView[A]
was previously trying to return anIndexedView[A]
ontransformation operations such as
filter
ortake
. Doing so sometimesrequired to evaluate the views elements to build an indexed sequence
from which to get an
IndexedView
(see the last case):Now
IndexedView[A]
returns only aView[A]
on such operations.Another solution would have been to have
IndexedView
based versions of all transformation operations that areView
based (i.e.IndexedView.Filter
,IndexedView.Map
). The drawback of that solution would be that we would duplicate all transformation operations (we would haveView.Filter
andIndexedView.Filter
, etc.), but the advantage would be that the fact that a collection is indexed would be preserved across transformations applied to its view.I discovered this issue while benchmarking the following code:
When
xs
was anIndexedSeq
, then it’sfilter
operation returnedfromSpecificIterable(View.Filter(…))
, which was converting theView.Filter(…)
into a strictIndexedSeq
to take its view.As a consequence, that code was (up to 2×) slower than the same code using strict transformation operations only (in red on the following chart):
With this PR, the version that uses views rather than strict transformation is slightly faster but still a bit slower than the strict version:
I’ve run a profiler and noticed that most of the time is spent on the
hasNext
operation. It is not clear to me why the view based version is still slower because in the strict version we also iterate on the same transformations and call the samehasNext
operations…