-
-
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
partition method seems to not work correctly, comparing to scala #2559
Comments
I used vavr 0.10.2 |
You are right! We need to change that. Generally, we focus on immutable objects. Your case is very special, because the predicate also mutates the object on every call. Normally, you would expect that a predicate reflects a state without changing the state. But I understand your concern, our goal is to align to Scala. The affected code lines in HashSet are: @Override
default Tuple2<Iterator<T>, Iterator<T>> partition(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
if (!hasNext()) {
return Tuple.of(empty(), empty());
} else {
final Stream<T> that = Stream.ofAll(this);
final Iterator<T> first = that.iterator().filter(predicate);
final Iterator<T> second = that.iterator().filter(predicate.negate());
return Tuple.of(first, second);
}
} Here we filter twice. We should do it in one turn. |
@kefasb, thanks for reporting and @danieldietrich, thanks for you hints. I sent PR #2577 to fix the problem. |
Thanks I will take a look! |
By default, Scala's def partition(p: A => Boolean): (C, C) = {
val first = new View.Filter(this, p, false)
val second = new View.Filter(this, p, true)
(fromSpecific(first), fromSpecific(second))
} Scala has so-called strict and lazy collections. The docs state that strict collections provide their own implementation in order to ensure that elements are iterated only twice:
Because Scala's Stream is already lazy, the default implementation of override def partition(p: A => Boolean): (Stream[A], Stream[A]) = (filter(p(_)), filterNot(p(_))) As pointed out by you, we already do the same because we align to Scala: @Override
public final Tuple2<Stream<T>, Stream<T>> partition(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return Tuple.of(filter(predicate), filter(predicate.negate()));
} Scala's def partition(p: A => Boolean): (Iterator[A], Iterator[A]) = {
val (a, b) = duplicate
(a filter p, b filterNot p)
} Scala's Iterator.duplicate method isn't trivial. I think it is sufficient to take the following actions:
|
@danieldietrich , I'm a bit lost and I need your help on this issue. So far, I created some tests to compare the behavior between Scala 2.13.2 and VAVR 1.0.0-SNAPSHOT, but I don't know which direction to continue. On Scala side, I created a Git repo and added a test
On VAVR side, I added a test in my PR as commit 42117bf to demonstrate the behavior of Several things confuse me here:
Personally I would like to use the one-iteration implementation as the default partition strategy. And override this strategy in |
Thank you for your analysis! That's interesting. We do it as follows:
We could create an infinite
No, I see currently no use-case. We already have
Sorry, I misunderstood the Scala implementation. There, the 1st step: Add
|
Thanks for your hints 👀 , Daniel! I will continue the work on it and ping you when I have progress. I'm not sure I can finish it today. If not, we may need to wait until next weekend. |
@mincong-h thanks! you don't need to rush |
Hello, I spotted a weird behaviour of partition method.
I include code examples from Java and Scala which I used to make the comparison.
Java
Scala
The Java output is:
(HashSet(), HashSet())
The Scala output is:
(Set(),Set(apple, banana))
I think the difference is because vavr traverses the collection and checks the predicate twice while scala does it once.
Is this a bug or expected behaviour?
The text was updated successfully, but these errors were encountered: