Loose end: concat

Brian Goetz brian.goetz at oracle.com
Thu May 23 14:57:33 PDT 2013


Same reason as into(Collection) -- these were the sole cases where the 
arguments to stream methods were stateful objects; everything else is a 
stateless recipe for how to transform a stream, but which does not 
intrinsically mutate or consume any of its arguments.

This wasn't just a philosophical concern, though I do believe it makes 
the API stronger.  The problems showed up immediately in our testing 
framework.  Our testing framework is based on repeatable stream 
transforms; we have an abstraction for "repeatable data source" (which 
can deliver its data as a stream, parallel stream, iterator, or 
spliterator), and tested stream operations using functions that 
transformed a stream into a stream:

   s -> s.map(i -> i*2)

With the repeatable data source, we were able to easily automate 
comparison between dozens of different ways to express the same result, 
such as:

   source.stream().map(...).toArray()
   source.parallelStream().map(...).toArray()
   source.stream().map(...).collect(toList())
   source.parallelStream().map(...).collect(toList())
   source.stream().map(...).iterator()
   ... etc

When we saw how much trouble methods like into() and concat() were for 
frameworks that want to build on the idea of "repeatable stream 
source/transform", this was a big warning sign; our test framework could 
not possibly be the only framework that would want to treat streams 
functionally.

Secondarily, the value of fluency here is pretty limited, since its 
likely that the other stream operation will be enough of a mouthful that 
it will get "outlined" anyway.

So bottom line: with into(Collection) and concat(Stream) removed, any 
function

   s -> s.streamOp(nonInterferingLambda)

becomes a repeatable and stateless transform.  No "except for ..." 
caveats needed.



On 5/23/2013 4:15 PM, Joe Bowbeer wrote:
> Why was an instance method rejected?  I can't recall.
>
> s = s1.concat(s2).concat(s3);
>
>
>
>
> On Thu, May 23, 2013 at 11:23 AM, Sam Pullara <spullara at gmail.com
> <mailto:spullara at gmail.com>> wrote:
>
>     *Stream seems like the right place for them to me. It is certainly
>     the second place I would look — first place would be as an instance
>     method, but we've discussed that before.
>
>     Sam
>
>     On May 23, 2013, at 11:06 AM, Brian Goetz <brian.goetz at oracle.com
>     <mailto:brian.goetz at oracle.com>> wrote:
>
>      > I cleaned up concat() and wrote Int/Long/Double versions.
>       (Fortunately, with the recent addition of Spliterator.OfPrimitive,
>     the duplication quotient was much lower.)
>      >
>      > Currently these still live in Streams.  Is that still the right
>     place? The stream classes (Stream, IntStream, etc) seem a little
>     wrong for them, but I can't quite put my finger on why.
>      >
>      > Specs:
>      >
>      >    /**
>      >     * Creates a lazy concatenated {@code Stream} whose elements
>     are all the
>      >     * elements of a first {@code Stream} succeeded by all the
>     elements of the
>      >     * second {@code Stream}. The resulting stream is ordered if both
>      >     * of the input streams are ordered, and parallel if either of
>     the input
>      >     * streams is parallel.
>      >     *
>      >     * @param <T> The type of stream elements
>      >     * @param a the first stream
>      >     * @param b the second stream to concatenate on to end of the
>     first
>      >     *        stream
>      >     * @return the concatenation of the two input streams
>      >     */
>      >    public static <T> Stream<T> concat(Stream<? extends T> a,
>     Stream<? extends T> b) {
>      >
>      >
>      >    /**
>      >     * Creates a lazy concatenated {@code IntStream} whose
>     elements are all the
>      >     * elements of a first {@code IntStream} succeeded by all the
>     elements of the
>      >     * second {@code IntStream}. The resulting stream is ordered
>     if both
>      >     * of the input streams are ordered, and parallel if either of
>     the input
>      >     * streams is parallel.
>      >     *
>      >     * @param a the first stream
>      >     * @param b the second stream to concatenate on to end of the
>     first stream
>      >     * @return the concatenation of the two streams
>      >     */
>      >    public static IntStream concat(IntStream a, IntStream b) {
>      >
>      >
>      > (and similar for Long and Double).
>      >
>
>


More information about the lambda-libs-spec-experts mailing list