Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return type inconsistency for SeqView/IndexedSeqView's tail/drop and init/dropRight methods #11745

Open
satorg opened this issue Sep 20, 2019 · 3 comments

Comments

@satorg
Copy link

commented Sep 20, 2019

Related to Scala Collections (2.13.0, 2.13.1)
Reproduced: always.

Actual:

These examples compile:

  • Seq(1).view.drop(1).distinct
  • IndexedSeq(1).view.dropRight(1).sorted

But these do not compile:

  • Seq(1).view.tail.distinct
  • IndexedSeq(1).view.init.sorted

This is because return type of both tail and init is simply View[Int],
although for drop/dropRight it is SeqView or IndexedSeqView respectively.

Expected:

The latter two examples should compile as well,
especially since tail and init are implemented as calls to drop and dropRight.

Reason:

The SeqView and IndexedSeqView implementations override methods such as drop and dropRight but not tail nor init, which thus inherited from IterableOps.

@satorg

This comment has been minimized.

Copy link
Author

commented Sep 25, 2019

I found out that this problem has more deep roots: since IndexedSeqView extends IndexedSeqOps[A, View, View[A]] (i.e. it passes a regular View as type parameter),
then all its transformation methods return View by default except those which are explicitly overridden in IndexedSeqView. The same is applicable to SeqView.

I'm wondering, is it done by design? At first glance it seems logical to extend IndexedSeqOps in this way: IndexedSeqOps[A, IndexedSeqView, IndexedSeqView[A], isn't it?

@SethTisue

This comment has been minimized.

Copy link
Member

commented Sep 30, 2019

@joshlemer thoughts?

@joshlemer

This comment has been minimized.

Copy link
Member

commented Oct 3, 2019

I'm wondering, is it done by design? At first glance it seems logical to extend IndexedSeqOps in this way: IndexedSeqOps[A, IndexedSeqView, IndexedSeqView[A], isn't it?

Unfortunately, this isn't so. If IndexedSeqView[A] extended IndexedSeqOps[A, IndexedSeqView, IndexedSeqView[A]], then all of the generic Iterable transformations would have to return IndexedSeqView[...], which they can't. For instance, filter could only return a View[A] or maybe a SeqView[A].

This gets to the question of "what is an IndexedSeqView[A] and how is it more special than a View or SeqView?", which I would say is something like this: an IndexedSeqView[A] supports random access (by index) of its data, without needing to force any other elements, and without needing to traverse the source collection linearly". This is only possible if the entire chain of computation starting from the source is index-preserving (map, take, dropRight) or at least predictably index-changing (drop, takeRight). filter, flatMap can map each source element to variable numbers of output, so you must evaluate each element of the view preceding an index, in order to produce the value at an index.

That being said, the problem that distinct and sorted are not available on View is not fundamental, and is unfortunate. In my opinion, they would ideally be available. They aren't available because View extends IterableOps, not SeqOps but maybe it should have extended SeqOps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.