RFR: 8072727 - add variation of Stream.iterate() that's finite
Stefan Zobel
spliterator at gmail.com
Mon Feb 15 17:15:39 UTC 2016
2016-02-15 7:48 GMT+01:00 Peter Levart <peter.levart at gmail.com>:
>
>
> What about even more permissive:
>
> static <T, S extends T> Stream<T> iterate3(S seed, Predicate<? super S>
> predicate, Function<? super S, ? extends S> f)
>
Hi Peter,
yes, Function<? super S, ? extends S> instead of UnaryOperator<S> is
indeed tempting.
On the other hand, for my taste, I find the wildcard-ridden signature
of iterate3 oversteps a certain complexity budget a little (that's
just my personal opinion, of course).
But you may be right - we already have such complex signatures in a
couple of other places. The question is, whether it would be really useful.
Regards,
Stefan
>
> public class SignatureTest {
>
> static <T> Stream<T> iterate1(T seed, Predicate<T> predicate,
> UnaryOperator<T> f) {
> ...
> }
>
> static <T, S extends T> Stream<T> iterate2(S seed, Predicate<S>
> predicate, UnaryOperator<S> f) {
> ...
> }
>
> static <T, S extends T> Stream<T> iterate3(S seed, Predicate<? super S>
> predicate, Function<? super S, ? extends S> f) {
> ...
> }
>
>
> public static void main(String[] args) {
>
> Stream<Integer> si1 = iterate1(0, i -> i < 10, i -> i + 1); // OK
> Stream<Integer> si2 = iterate2(0, i -> i < 10, i -> i + 1); // OK
> Stream<Integer> si3 = iterate3(0, i -> i < 10, i -> i + 1); // OK
>
> Stream<Number> sn1 = iterate1(0, i -> i < 10, i -> i + 1);
>
> //SignatureTest.java:32: error: bad operand types for binary
> operator '<'
> // Stream<Number> sn1 = iterate1(0, i -> i < 10, i -> i + 1);
> // ^
> //SignatureTest.java:32: error: bad operand types for binary
> operator '+'
> // Stream<Number> sn1 = iterate1(0, i -> i < 10, i -> i + 1);
> // ^
>
>
> Stream<Number> sn2 = iterate2(0, i -> i < 10, i -> i + 1); // OK
> Stream<Number> sn3 = iterate3(0, i -> i < 10, i -> i + 1); // OK
>
>
> Predicate<CharSequence> csNotEmpty = cs -> cs.length() > 0;
>
> Stream<CharSequence> css1 = iterate1("abcde", csNotEmpty, (String s)
> -> s.substring(1));
>
> //SignatureTest.java:44: error: method iterate1 in class
> SignatureTest cannot be applied to given types;
> // Stream<CharSequence> css1 = iterate1("abcde", csNotEmpty,
> (String s) -> s.substring(1));
> // ^
> // required: T,Predicate<T>,UnaryOperator<T>
> // found: String,Predicate<CharSequence>,(String s)[...]ng(1)
> // reason: inference variable T has incompatible equality
> constraints String,CharSequence
> // where T is a type-variable:
> // T extends Object declared in method
> <T>iterate1(T,Predicate<T>,UnaryOperator<T>)
>
>
> Stream<CharSequence> css2 = iterate2("abcde", csNotEmpty, (String s)
> -> s.substring(1));
>
> //SignatureTest.java:54: error: method iterate2 in class
> SignatureTest cannot be applied to given types;
> // Stream<CharSequence> css2 = iterate2("abcde", csNotEmpty,
> (String s) -> s.substring(1));
> // ^
> // required: S,Predicate<S>,UnaryOperator<S>
> // found: String,Predicate<CharSequence>,(String s)[...]ng(1)
> // reason: inference variable S has incompatible equality
> constraints String,CharSequence
> // where S,T are type-variables:
> // S extends T declared in method
> <T,S>iterate2(S,Predicate<S>,UnaryOperator<S>)
> // T extends Object declared in method
> <T,S>iterate2(S,Predicate<S>,UnaryOperator<S>)
>
>
> Stream<CharSequence> css3 = iterate3("abcde", csNotEmpty, (String s)
> -> s.substring(1)); // OK
> }
> }
>
>
> Regards, Peter
>
>
>
> Regards,
> Stefan
>
>
> 2016-02-14 15:53 GMT+01:00 Tagir F. Valeev <amaembo at gmail.com>:
>
> Hello!
>
> I wanted to work on foldLeft, but Brian asked me to take this issue
> instead. So here's webrev:
> http://cr.openjdk.java.net/~tvaleev/webrev/8072727/r1/
>
> I don't like iterator-based Stream source implementations, so I made
> them AbstractSpliterator-based. I also implemented manually
> forEachRemaining as, I believe, this improves the performance in
> non-short-circuiting cases.
>
> I also decided to keep two flags (started and finished) to track the
> state. Currently existing implementation of infinite iterate() does
> not use started flag, but instead reads one element ahead for
> primitive streams. This seems wrong to me and may even lead to
> unexpected exceptions (*). I could get rid of "started" flag for
> Stream.iterate() using Streams.NONE, but this would make object
> implementation different from primitive implementations. It would also
> be possible to keep single three-state variable (byte or int,
> NOT_STARTED, STARTED, FINISHED), but I doubt that this would improve
> the performance or footprint. Having two flags looks more readable to
> me.
>
> Currently existing two-arg iterate methods can now be expressed as a
> partial case of the new method:
>
> public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
> return iterate(seed, x -> true, f);
> }
> (same for primitive streams). I may do this if you think it's
> reasonable.
>
> I created new test class and added new iterate sources to existing
> data providers.
>
> Please review and sponsor!
>
> With best regards,
> Tagir Valeev.
>
> (*) Consider the following code:
>
> int[] data = {1,2,3,4,-1};
> IntStream.iterate(0, x -> data[x])
> .takeWhile(x -> x >= 0)
> .forEach(System.out::println);
>
> Currently this unexpectedly throws an AIOOBE, because
> IntStream.iterate unnecessarily tries to read one element ahead.
>
>
More information about the core-libs-dev
mailing list