Loose end: spliterator() and stream() methods on Iterable

Brian Goetz brian.goetz at oracle.com
Tue Jun 25 09:46:31 PDT 2013


Yes, that would address the early binding defect.  We at one point had a 
class that did just this, but I think it got refactored away, though it 
could be easily reconstructed.  Its simple but boilerplate-laden.

Even without this additional tip, I think the scales still tilt slightly 
in favor of inclusion.  The impl may be crappy, but it still helps the 
clients.  Imagine:

   Iterable<T> someLibFn(...);

and a caller of someLibFn who receives an Iterable and wants a Stream. 
Now, in reality, this Iterable probably *is* a Collection, so it 
probably *does* provide a better spliterator.  Being able to say

   Stream s = StreamSupport.stream(iter::spliterator)

actually does get them a good stream implementation if spliterator() has 
been overridden.  Wheras without spliterator() being on iterator(), 
they're forced to get a bad spliterator anyway, even when a good one is 
available.

So the moral hazard of lazy Iterable devs not overriding spliterator() 
is real, but the alternative (leave it out) hurts the users 
unconditionally anyway.

Any comments on the proposed spec?

On 6/25/2013 12:38 PM, Tim Peierls wrote:
> Not denying the badness of the default implementation, but could it be
> improved (very slightly) by defining and then using a variant of
> spliteratorUnknownSize that takes a Supplier<Iterator> rather than an
> Iterator? Only relevant if you were looking to tip the scales.
>
> --tim
>
> On Tue, Jun 25, 2013 at 11:27 AM, Brian Goetz <brian.goetz at oracle.com
> <mailto:brian.goetz at oracle.com>> wrote:
>
>     As I try to specify even this small addition, I'm still not sure :(
>
>     The default implementation -- which is just
>
>        return Spliterators.__spliteratorUnknownSize(__iterator(), 0);
>
>     should almost always be overriden.  It has crappy parallelism,
>     doesn't know its size, doesn't know any other spliterator
>     characteristics, and is early-binding -- the "grand slam" of bad
>     spliterators.
>
>     The downside is that people will not override spliterator() and
>     result in bad streams.  The upside is that then Iterable *has* a
>     spliterator() method, which reduces the effort for *clients* to make
>     streams out of Iterables.
>
>     Here's what I've got so far:
>
>          /**
>           * Creates a {@link Spliterator} over the elements described by
>     this
>           * {@code Iterable}.
>           *
>           * @implSpec
>           * <p>The default implementation should almost always be
>     overridden.  The
>           * spliterator returned by the default implementation has poor
>     splitting
>           * characteristics, is unsized (and does not report any other
>     spliterator
>           * characteristics), and is <em><a
>     href="Spliterator.html#__binding">early-binding</a></__em>.
>           * Implementating classes can nearly always provide a better
>     implementation.
>           * The returned spliterator inherits the <em>fail-fast</em>
>     properties of the
>           * collection's iterator.
>           *
>           * @return a {@code Spliterator} over the elements described by
>     this
>           * {@code Iterable}.
>           * @since 1.8
>           */
>          default Spliterator<T> spliterator() {
>              return Spliterators.__spliteratorUnknownSize(__iterator(), 0);
>
>          }
>
>
>
>     On 6/25/2013 6:39 AM, Paul Sandoz wrote:
>
>
>         On Jun 24, 2013, at 11:41 PM, Remi Forax <forax at univ-mlv.fr
>         <mailto:forax at univ-mlv.fr>> wrote:
>
>             On 06/24/2013 09:40 PM, Brian Goetz wrote:
>
>                 After further thought, I think what this means is that
>                 we can move spliterator() up to Iterable, but not
>                 stream().  The reason for this is that some classes that
>                 implement Iterable<Integer> might prefer that their
>                 stream() method return an IntStream, not be forced into
>                 a Stream<Integer>.  So putting stream() too high up in
>                 the hierarchy forecloses on this.
>
>
>             I agree,
>
>
>         +1
>
>         Paul.
>
>
>             Spliterator.OfInt is a Spliterator but IntStream is not a
>             Stream.
>
>             Rémi
>
>


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