-
-
Notifications
You must be signed in to change notification settings - Fork 638
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
Add tap() and/or tapEach() methods #2676
Comments
let's do it! It is great to sync with Scala. Could you clarify the difference between/define the semantics of peek/tap, forEach/tapEach? |
OK, first of all, I just saw that
public final class VavrX {
public static <T> Function<T, T> touch(Consumer<? super T> consumer) {
return v -> {
consumer.accept(v);
return v;
};
}
} So, Let's look at this small program: public class Tap {
public static void main(String[] args) {
var src = List.of(1, 2, 3);
System.out.println("peek()");
src.peek(i -> System.out.println("in: " + 1))
.map(Tap::dup)
.forEach(i -> System.out.println("out: " + i));
System.out.println("toStream().peek()");
src.toStream()
.peek(i -> System.out.println("in: " + 1))
.map(Tap::dup)
.forEach(i -> System.out.println("out: " + i));
System.out.println("map(touch())");
src.map(touch(i -> System.out.println("in: " + i)))
.map(Tap::dup)
.forEach(i -> System.out.println("out: " + i));
}
public static int dup(int i) {
return i * 2;
}
} The output of this is:
The
So, the last variant with System.out.println("tapEach()");
src.tapEach(i -> System.out.println("in: " + i))
.map(Tap::dup)
.forEach(i -> System.out.println("out: " + i)); Edit: For the sake of completeness, here's the
Output:
Again, |
@sleepytomcat this would be a good issue: interface Traversable<T> {
// javadoc
Traversable<T> tapEach(Consumer<? super T> action);
} It needs to be implemented on each collection interface Seq<T> extends Traversable<T> {
@Override
Seq<T> tapEach(Consumer<? super T> action);
}
interface List<T> extends LinearSeq<T> {
@Override
default List<T> tapEach(Consumer<? super T> action) {
return Collections.tapEach(this, action);
}
}
// existing utility class
final class Collections {
static <T, C extends Traversable<T>> C tapEach(C source, Consumer<? super T> action) {
return source.map(t -> {
action.accept(t);
return t;
});
}
} Regarding the tests, I would love to see general AbstractTraversable tests, also for the expected order of side-effects. Maybe we need additional tests for Stream and Iterator (the lazily evaluated structures) because they behave slightly different but I'm not sure... I would use a javadoc for What do you think? |
when can we use the v1.0.0? Need for this feature badly~ |
@danieldietrich @Abnaxos I'm addressing this in #2676, need some clarification on how we actually want to connect Scala and Vavr logic here.
https://www.scala-lang.org/api/2.13.6/scala/collection/immutable/Stream.html#tapEach[U](f:A=%3EU):C Specifically this part: "lazy collections [...] will only apply f on each element if and when that element is evaluated, and each time that element is evaluated".
— here the output would be:
My point is, directly applying Scala logic from (1) to Vavr design (2) would result in
Output:
I believe this is not what we want. All of the above makes me think we may need to clarify the rules (exception from the rules?) of materializing/evaluating elements of a Stream in Vavr to be able to implement |
Collections, Options etc. should have a
tap(Consumer<? super T>)
method.This is related to #2424, where I criticised the inconsistent behaviour of
peek()
. I still do, BTW.Problem at hand: there has to be a way to call a function on each element of a collection/option/etc solely for its side-effect (e.g. logging).
peek()
isn't the right method for this, because depending on the underlying implementation, it may only be applied to the first element of the collection. AFAIK, you can usemySeq.toSteam().peek(e -> ...)
to make sure that the function will be applied to each element, but I consider this dangerous (just forgettoStream()
and you don't know, how exactlypeek()
will behave, it may not do what you wanted it to do – this can be hard to spot).Scala 2.13 introduced
tap()
andtapEach()
for this purpose. Add this to Vavr as well.The text was updated successfully, but these errors were encountered: