Hello! Thank you for your comments. The thing which is absolutely necessary is to make PECS Predicate signature (for some reason I forgot it):
static <T> Stream<T> iterate(T seed, Predicate<? super T> predicate, UnaryOperator<T> f) { ... } While you cannot readily make Stream<Number> from it, it's not a big problem if the stream has more specific type. For example, you still can collect to the List<Number>. This code works perfectly: List<Number> list = iterate(0, i -> i < 10, i -> i + 1).collect(Collectors.toList()); Predicate<CharSequence> csNotEmpty = cs -> cs.length() > 0; List<CharSequence> result = iterate("abcde", csNotEmpty, (String s) -> s.substring(1)) .collect(Collectors.toList()); Any functions appearing in the intermediate/terminal operations should also be fine with more concrete type (even if they are specified not as lambdas, but as actual interfaces like Function<X, Y>). The only problem which iterate3 would solve is when you actually need the stream of particular type (for example, you're implementing the interface method which returns exactly Stream<Number>). I think it's quite rare case and you can always add map step to solve this (if you don't like unchecked cast): Stream<Number> sn4 = iterate(0, i -> i < 10, i -> i + 1).map(Number.class::cast); Probably it's still reasonable to introduce second type variable, but for conformance with existing signatures of Stream.generate, Stream.iterate I would prefer not to stay with <T> only. Or probably all these methods should be updated at once (this could be considered as separate issue). With best regards, Tagir Valeev. PL> On 02/14/2016 07:15 PM, Stefan Zobel wrote: PL> PL> PL> Hi Tagir, PL> this looks good. I wonder, however, if the signature should PL> accept a wider range of types, i.e., something like PL> static <T, S extends T> Stream<T> iterate(S seed, Predicate<S> PL> predicate, UnaryOperator<S> f) PL> I know that the corresponding PL> static <T> Stream<T> iterate(T seed, UnaryOperator<T> f) PL> is less general than that, but I don't know whether this is PL> the outcome of a thoughtful decision or just an oversight. PL> What do you think? PL> PL> PL> What about even more permissive: PL> PL> static <T, S extends T> Stream<T> iterate3(S seed, PL> Predicate<? super S> predicate, Function<? super S, ? extends S> f) PL> PL> ... PL> PL> public class SignatureTest { PL> PL> static <T> Stream<T> iterate1(T seed, Predicate<T> predicate, UnaryOperator<T> f) { PL> ... PL> } PL> PL> static <T, S extends T> Stream<T> iterate2(S seed, PL> Predicate<S> predicate, UnaryOperator<S> f) { PL> ... PL> } PL> PL> static <T, S extends T> Stream<T> iterate3(S seed, PL> Predicate<? super S> predicate, Function<? super S, ? extends S> f) { PL> ... PL> } PL> PL> PL> public static void main(String[] args) { PL> PL> Stream<Integer> si1 = iterate1(0, i -> i < 10, i -> i + 1); // OK PL> Stream<Integer> si2 = iterate2(0, i -> i < 10, i -> i + 1); // OK PL> Stream<Integer> si3 = iterate3(0, i -> i < 10, i -> i + 1); // OK PL> PL> Stream<Number> sn1 = iterate1(0, i -> i < 10, i -> i + 1); PL> PL> //SignatureTest.java:32: error: bad operand types for binary operator '<' PL> // Stream<Number> sn1 = iterate1(0, i -> i < 10, i -> i + 1); PL> // ^ PL> //SignatureTest.java:32: error: bad operand types for binary operator '+' PL> // Stream<Number> sn1 = iterate1(0, i -> i < 10, i -> i + 1); PL> // PL> PL> PL> Stream<Number> sn2 = iterate2(0, i -> i < 10, i -> i + 1); // OK PL> Stream<Number> sn3 = iterate3(0, i -> i < 10, i -> i + 1); // OK PL> PL> PL> Predicate<CharSequence> csNotEmpty = cs -> cs.length() > 0; PL> PL> Stream<CharSequence> css1 = iterate1("abcde", PL> csNotEmpty, (String s) -> s.substring(1)); PL> PL> //SignatureTest.java:44: error: method iterate1 in PL> class SignatureTest cannot be applied to given types; PL> // Stream<CharSequence> css1 = PL> iterate1("abcde", csNotEmpty, (String s) -> s.substring(1)); PL> // ^ PL> // required: T,Predicate<T>,UnaryOperator<T> PL> // found: String,Predicate<CharSequence>,(String s)[...]ng(1) PL> // reason: inference variable T has incompatible PL> equality constraints String,CharSequence PL> // where T is a type-variable: PL> // T extends Object declared in method PL> <T>iterate1(T,Predicate<T>,UnaryOperator<T>) PL> PL> PL> Stream<CharSequence> css2 = iterate2("abcde", PL> csNotEmpty, (String s) -> s.substring(1)); PL> PL> //SignatureTest.java:54: error: method iterate2 in PL> class SignatureTest cannot be applied to given types; PL> // Stream<CharSequence> css2 = PL> iterate2("abcde", csNotEmpty, (String s) -> s.substring(1)); PL> // ^ PL> // required: S,Predicate<S>,UnaryOperator<S> PL> // found: String,Predicate<CharSequence>,(String s)[...]ng(1) PL> // reason: inference variable S has incompatible PL> equality constraints String,CharSequence PL> // where S,T are type-variables: PL> // S extends T declared in method PL> <T,S>iterate2(S,Predicate<S>,UnaryOperator<S>) PL> // T extends Object declared in method PL> <T,S>iterate2(S,Predicate<S>,UnaryOperator<S>) PL> PL> PL> Stream<CharSequence> css3 = iterate3("abcde", PL> csNotEmpty, (String s) -> s.substring(1)); // OK PL> } PL> } PL> PL> PL> Regards, Peter PL> PL> PL> PL> Regards, PL> Stefan PL> 2016-02-14 15:53 GMT+01:00 Tagir F. Valeev <amae...@gmail.com>: PL> PL> PL> Hello! PL> I wanted to work on foldLeft, but Brian asked me to take this issue PL> instead. So here's webrev: PL> http://cr.openjdk.java.net/~tvaleev/webrev/8072727/r1/ PL> I don't like iterator-based Stream source implementations, so I made PL> them AbstractSpliterator-based. I also implemented manually PL> forEachRemaining as, I believe, this improves the performance in PL> non-short-circuiting cases. PL> I also decided to keep two flags (started and finished) to track the PL> state. Currently existing implementation of infinite iterate() does PL> not use started flag, but instead reads one element ahead for PL> primitive streams. This seems wrong to me and may even lead to PL> unexpected exceptions (*). I could get rid of "started" flag for PL> Stream.iterate() using Streams.NONE, but this would make object PL> implementation different from primitive implementations. It would also PL> be possible to keep single three-state variable (byte or int, PL> NOT_STARTED, STARTED, FINISHED), but I doubt that this would improve PL> the performance or footprint. Having two flags looks more readable to PL> me. PL> Currently existing two-arg iterate methods can now be expressed as a PL> partial case of the new method: PL> public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) { PL> return iterate(seed, x -> true, f); PL> } PL> (same for primitive streams). I may do this if you think it's PL> reasonable. PL> I created new test class and added new iterate sources to existing PL> data providers. PL> Please review and sponsor! PL> With best regards, PL> Tagir Valeev. PL> (*) Consider the following code: PL> int[] data = {1,2,3,4,-1}; PL> IntStream.iterate(0, x -> data[x]) PL> .takeWhile(x -> x >= 0) PL> .forEach(System.out::println); PL> Currently this unexpectedly throws an AIOOBE, because PL> IntStream.iterate unnecessarily tries to read one element ahead. PL> PL> PL> PL>