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

Peek operation for sequences and iterables #47

Closed
ilya-g opened this issue Aug 29, 2016 · 16 comments
Closed

Peek operation for sequences and iterables #47

ilya-g opened this issue Aug 29, 2016 · 16 comments
Assignees
Labels

Comments

@ilya-g
Copy link
Member

ilya-g commented Aug 29, 2016

Discussions about the onEach operation for sequences and iterables will be held here.

@ilya-g ilya-g added the stdlib label Aug 29, 2016
@ilya-g ilya-g self-assigned this Aug 29, 2016
ilya-g added a commit that referenced this issue Aug 29, 2016
@ilya-g
Copy link
Member Author

ilya-g commented Aug 29, 2016

Do we need peek for Iterables at all?
Some counter-arguments:

  • can be expressed with apply { forEach { ... } }
    • pro: semantics is clear
    • con: hides this
  • intermediate operations on Iterable usually copy the source collection, it may be hard to tell what would be the behavior of peek
  • can be confused with Queue.peek().

@JakeWharton
Copy link

JakeWharton commented Aug 29, 2016

I like the name onEach as a complement to forEach since it further implies that this is purely used as a side-effect operation in the stream/chain.

@ilya-g
Copy link
Member Author

ilya-g commented Aug 29, 2016

Should peek delegate to map for Sequences?

We plan to make some optimizations of map operation for sequences, it would be beneficial if peek could exploit those optimizations without having to reimplement them.

To implement peek with map we have to wrap the operation in the following lambda:
{ operation(it); it }

We could either inline the operation in that lambda or not. The performance consequences of that options should be studied for both cases: when the operation is specified as a lambda itself peek { println(it) }, or passed as a functional type peek(operation).

@cbruegg
Copy link
Contributor

cbruegg commented Aug 29, 2016

Peek for Iterables

can be expressed with apply { forEach { ... } }

Another con: It creates another nested layer of curly braces and thus more indentation in many cases.

intermediate operations on Iterable usually copy the source collection, it may be hard to tell what would be the behavior of peek

I have to agree here - the behavior definitely differs from Sequence.peek and could cause misunderstanding.

sequenceOf(1, 2).peek { println(it * 2) }.forEach { println(it) } would yield

2
1
4
2

while

listOf(1, 2).peek { println(it * 2) }.forEach { println(it) } would yield

2
4
1
2

can be confused with Queue.peek()

That would be sorted out by renaming peek to onEach - perhaps only Iterable.peek -> Iterable.onEach, but not Sequence.peek -> Sequence.onEach, to reflect the differences in behavior. A downside would be decreased discoverability.

Performance

The performance consequences of that options should be studied for both cases

Unfortunately I don't have much experience with this, especially since there may be differences between various VM implementations like ART, Dalvik and the JVM due to the JITs.

@ilya-g
Copy link
Member Author

ilya-g commented Sep 15, 2016

That would be sorted out by renaming peek to onEach - perhaps only Iterable.peek -> Iterable.onEach, but not Sequence.peek -> Sequence.onEach, to reflect the differences in behavior. A downside would be decreased discoverability.

The difference in evaluation order is not an issue, the same difference is observed if you change peek to map for example.
After some contemplation I think onEach is a good name both for Iterable and Sequence.

@ilya-g
Copy link
Member Author

ilya-g commented Sep 16, 2016

I believe it's the time to implement a prototype. You can either craft it as a pull request to the kotlin standard library if you're familiar with stdlib code generator or write manually in any other repository.

@ilya-g
Copy link
Member Author

ilya-g commented Sep 16, 2016

Some implementation notes:

  • Iterable<T>.onEach returns the receiver itself, so it would be good to have the return type preserving the type of the receiver.
  • onEach could be provided for other types of receivers that already have forEach.

@cbruegg
Copy link
Contributor

cbruegg commented Sep 17, 2016

If I understood the DSL correctly, something like this should work. Ant kept crashing for me and I'm getting Could not find artifact org.jetbrains.kotlin:kotlin-maven-plugin:pom:1.1-SNAPSHOT when executing the maven goal compile exec:java on the generator, so unfortunately I wasn't able to test it.

@matklad
Copy link

matklad commented Sep 22, 2016

peek is a really confusing name imo, because peek as "look at the next element, but don't call next" also makes sense for iterators. Rust uses the name inspect for this function, I think it is a good choice.

@ilya-g
Copy link
Member Author

ilya-g commented Oct 3, 2016

@cbruegg not quite right, but ok for starting point. I've elaborated those templates a bit, it required to improve the DSL to support such non-trivial constraints on generic receiver.

The result is available in rr/stdlib/oneach branch. Could you check it out and try it with some tests?

@cbruegg
Copy link
Contributor

cbruegg commented Oct 14, 2016

@ilya-g Sorry for the late response and thanks for fixing the template. I've had a look at the generated code and tried it out with some tests and everything seems to work as expected. I really like how we were able to implement this using map and apply, which makes the generated code easily verifiable for correctness.

Personally, I think this looks pretty much complete.

@ilya-g
Copy link
Member Author

ilya-g commented Nov 25, 2016

Since we'd like to avoid inflating method count in stdlib, we're going not to provide onEach for arrays. Otherwise, all looks good and we'll merge rr/stdlib/oneach branch soon.

ilya-g added a commit that referenced this issue Nov 25, 2016
… alternatives. Finalize name by replacing 'peek' with 'onEach' and renaming the proposal file itself.
@cbruegg
Copy link
Contributor

cbruegg commented Nov 25, 2016

Great, thank you for having worked on this! It's always great to see that JetBrains is really listening to feedback.

ilya-g added a commit that referenced this issue Dec 4, 2016
@ilya-g ilya-g closed this as completed Mar 15, 2017
@elect86
Copy link

elect86 commented Jun 20, 2019

What about onEachIndexed?

@haug-den-lucas
Copy link

Wanted to reask, what is about onEachIndexed?

@ilya-g
Copy link
Member Author

ilya-g commented Mar 2, 2020

I think that onEachIndexed can be useful.
Could you provide some motivating examples for this function?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants