Initial prototype for BiStream (renamed to MapStream)

Peter Levart peter.levart at gmail.com
Sun May 6 15:25:49 PDT 2012


Hi Mike, Brian,

I have experimented with a thechique that uses "push" instead of "pull" (like 
Iterable or MapStream). Here's the result:

https://github.com/plevart/PushPipes

Pipe is a pair to Iterable
BiPipe is a pair to MapStream

I tried to implement most of the operations present in Iterable and MapStream.

There are pros and cons to this approach.

Pros: 
- No box/unbox-ing of intermediate results (BiValue-s)
- The code for various operations seems to be much simpler

Con: 
- References in the chain of operations are in direction parent -> child (as 
opposed to child -> parent with pull approach of Iterator/MapStream), so each 
parent can only have one child (you can not re-use half built chain to build 
two different continuations).

What dou you think?

Regards, Peter


On Wednesday, April 25, 2012 05:33:31 PM Mike Duigou wrote:
> Or, if you are the type of person who likes to be their explanations to be
> entertaining:
> 
> http://youtu.be/wbp-3BJWsU8?t=10m20s
> 
> which was bug:
> 
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6312706
> 
> Mike
> 
> On Apr 25 2012, at 15:36 , Rémi Forax wrote:
> > Hi Peter,
> > The original implementation of IdentityHashMap was based on the same
> > idea, reusing Map.Entry implementation, and it didn't work well.
> > 
> > Full story here:
> > http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6232484
> > 
> > Rémi
> > 
> > On 04/26/2012 12:25 AM, Peter Levart wrote:
> >> On Wednesday, April 18, 2012 03:39:28 PM Mike Duigou wrote:
> >>> There's a big question lurking in the implementation involving
> >>> boxing/unboxing of BiValue<L,R>  as used by the BiBlock, BiMapper and
> >>> Predicate.
> >> 
> >> I don't know if this is a good idea, but pragmatic approach could be to
> >> re-use the intermediate BiValues and control manually if you need
> >> BiValue(s) by reference or just momentarily for extracting the
> >> components (i.e. whether the reference to BiValue "escapes" the
> >> iteration step or not).
> >> 
> >> For example:
> >> 
> >> public abstract class BiValueStream<T, U>  implements Iterable<BiValue<T,
> >> U>> {
> >> 
> >>    private boolean reuseResult = true;
> >>    
> >>    private static class BiVal<T, U>  implements BiValue<T, U>
> >>    {
> >>    
> >>       private T left;
> >>       private U right;
> >>       
> >>       @Override
> >>       public T left()
> >>       {
> >>       
> >>          return left;
> >>       
> >>       }
> >>       
> >>       @Override
> >>       public U right()
> >>       {
> >>       
> >>          return right;
> >>       
> >>       }
> >>    
> >>    }
> >>    
> >>    <V>  BiValueStream<T, V>  map(final BiMapper<T, U, V>  mapper)
> >>    {
> >>    
> >>       return new BiValueStream<T, V>()
> >>       {
> >>       
> >>          @Override
> >>          public Iterator<BiValue<T, V>>  iterator()
> >>          {
> >>          
> >>             final Iterator<BiValue<T, U>>  source =
> >>             BiValueStream.this.iterator();
> >>             
> >>             return new Iterator<BiValue<T, V>>()
> >>             {
> >>             
> >>                @Override
> >>                public boolean hasNext()
> >>                {
> >>                
> >>                   return source.hasNext();
> >>                
> >>                }
> >>                
> >>                private BiVal<T, V>  reusableResult = reuseResult ? new
> >>                BiVal<T, V>() : null;
> >>                
> >>                @Override
> >>                public BiValue<T, V>  next()
> >>                {
> >>                
> >>                   BiValue<T, U>  next = source.next();
> >>                   BiVal<T, V>  result = reuseResult ? reusableResult :
> >>                   new BiVal<T, V>();
> >>                   result.left = next.left();
> >>                   result.right = mapper.map(next.left(), next.right());
> >>                   return result;
> >>                
> >>                }
> >>             
> >>             };
> >>          
> >>          }
> >>       
> >>       };
> >>    
> >>    }
> >>    
> >>    public BiValueStream<T, U>  reuseResult(boolean reuseResult)
> >>    {
> >>    
> >>       this.reuseResult = reuseResult;
> >>       return this;
> >>    
> >>    }
> >> 
> >> }
> >> 
> >> 
> >> // an example where BiVal is resused:
> >> 
> >> BiValueStream<String, String>  keyVals = ...;
> >> Map<String, Integer>  keyValLengths = new HashMap<>();
> >> 
> >> for (BiValue<String, Integer>  keyValLength : keyVals.map((key, val) -> 
> >> key.length() + val.length())) {
> >> 
> >>    keyValLengths.put(keyValLength.left(), keyValLength.right());
> >> 
> >> }
> >> 
> >> // and where it is not:
> >> 
> >> List<BiValue<String, Integer>>  keyValLengthList = new ArrayList<>();
> >> 
> >> for (BiValue<String, Integer>  keyValLength : keyVals.map((key, val) -> 
> >> key.length() + val.length()).reuseResult(false)) {
> >> 
> >>    keyValLengthList.add(keyValLength);
> >> 
> >> }
> >> 
> >> 
> >> ...usually, when you chain transformations, you don't need intermediate
> >> BiValues by reference, just the components. Only at the end you may need
> >> them.
> >> 
> >> 
> >> Regards,
> >> Peter


More information about the lambda-dev mailing list