Design for collections upgrades (was: Re: lambda-dev Digest, Vol 15, Issue 20 [reduce method result type])
Peter Levart
peter.levart at marand.si
Thu Mar 10 04:10:38 PST 2011
On 03/08/11, Brian Goetz wrote:
> 2. Serial / Lazy. Here, the primary abstraction is Stream (name to be
> chosen later, Remi used "lazy" in his example.) To transfer between
> "eager world" and "lazy world", you use conversion methods (toStream /
> toCollection). A typical call chain probably looks like:
> collection.toStream / op / op / op / {toCollection,reduce,apply}
>
> so the above example becomes
>
> maxFooWeight = things.asStream()
> .filter(#Thing.isFoo)
> .map(#Thing.getWeight)
> .max();
Is there a need for new type "Stream" other than to be able to position it at a more "appropriate" place in types hierarchy? Is Stream going to be any different from java.lang.Iterable from API perspective?
Maybe we don't need another type. Collections framework choose not to staticaly differentiate between mutable and immutable collections which has prooven to be usefull in lots of ways. More types make APIs less interoperable.
I've played with the following idea and I think it could more or less satisfy a large specrtum of use-cases and users:
Let Iterable by default (via defender methods) be lazy but let Collection (also via defender methods) override the same methods an make them eager. Also privide two methods to switch between eager and lazy on the Iterable itself (and override in Collection and subtypes).
This way you get the same usage pattern for Collections (eager by default) and we don't need another type.
To express this more clearly, I provide sample Iterable/Collection/List/Set interfaces:
public interface Iterable<T>
{
Iterator<T> iterator();
// eager/lazy switching
// iterables are by default lazy (unless overriden by a subtype such as Collection)
Iterable<T> toLazy(); // default Defenders.iterableToSelf;
// collect to ArrayList by default
Collection<T> toEager(); // default Defenders.iterableToArrayList;
// lazy filter/map...
Iterable<T> filter(Predicate<? super T> predicate) default Defenders.iterableLazyFilter;
<R> Iterable<R> map(Mapper<? super T, ? extends R> mapper) default Defenders.iterableLazyMap;
// collecting/filtering/mapping to provided instance
<C extends Collection<? super T>> C addTo(C collection) default Defenders.iterableAddTo;
<C extends Collection<? super T>> C filterTo(C collection) default Defenders.iterableFilterTo;
<C extends Collection<? super T>> C mapTo(C collection) default Defenders.iterableMapTo;
}
public interface Collection<E> extends Iterable<E>
{
// Collection methods
// ...
// eager/lazy switching
// wrap with lazy iterable
Iterable<E> toLazy() default Defenders.iterableWrapWithLazyIterable;
// collections are eager by default
Collection<E> toEager() default Defenders.iterableToSelf;
// overriden by covariant and eager filter/map...
Collection<E> filter(Predicate<? super E> predicate) default Defenders.iterableFilterToArrayList;
<R> Collection<R> map(Mapper<? super E, ? extends R> mapper) default Defenders.iterableMapToArrayList;
}
public interface List<E> extends Collection<E>
{
// List methods
// ...
// eager/lazy switching
// override with covariant return
List<E> toEager(); // default Defenders.iterableToSelf;
// eager filter/map...
// override with covariant return
List<E> filter(Predicate<? super E> predicate); // default Defenders.iterableFilterToArrayList;
// override with covariant return
<R> List<R> map(Mapper<? super E, ? extends R> mapper); // default Defenders.iterableMapToArrayList;
}
public interface Set<E> extends Collection<E>
{
// Set methods
// ...
// eager/lazy switching
// override with covariant return
Set<E> toEager(); // default Defenders.iterableToSelf;
// eager filter/map...
// override with covariant return
Set<E> filter(Predicate<? super E> predicate); // default Defenders.iterableFilterToHashSet;
// override with covariant return
<R> Set<R> map(Mapper<? super E, ? extends R> mapper); // default Defenders.iterableMapToHashSet;
}
...and for completeness, here is also the signatures of Defenders static methods:
public class Defenders
{
// lazy/eager wraping/conversion
public static <T, I extends Iterable<T>> I iterableToSelf(I self)
public static <T> Iterable<T> iterableWrapWithLazyIterable(Iterable<T> self)
public static <T> List<T> iterableToArrayList(Iterable<T> self)
public static <T> Set<T> iterableToHashSet(Iterable<T> self)
// eager filter/map
public static <T> Collection<T> iterableFilterToArrayList(Iterable<T> self, Predicate<? super T> predicate)
public static <S, T> Collection<T> iterableMapToArrayList(Iterable<S> self, Mapper<? super S, ? extends T> mapper)
public static <T> Set<T> iterableFilterToHashSet(Iterable<T> self, Predicate<? super T> predicate)
public static <S, T> Set<T> iterableMapToHashSet(Iterable<S> self, Mapper<? super S, ? extends T> mapper)
// lazy filter/map
public static <T> Iterable<T> iterableLazyFilter(final Iterable<T> self, final Predicate<? super T> predicate)
public static <S, T> Iterable<T> iterableLazyMap(final Iterable<S> self, final Mapper<? super S, ? extends T> mapper)
// collecting/filtering/mapping to provided instance
public static <T, C extends Collection<? super T>> C iterableAddTo(Iterable<T> self, C targetCollection)
public static <T, C extends Collection<T>> C iterableFilterTo(Iterable<T> self, Predicate<? super T> predicate, C targetCollection)
public static <S, T, C extends Collection<T>> C iterableMapTo(Iterable<S> self, Mapper<? super S, ? extends T> mapper, C targetCollection)
}
Regards, Peter
More information about the lambda-dev
mailing list