London Lambdas Hackday: Developer Practices

Brian Goetz brian.goetz at oracle.com
Tue Jul 3 23:09:52 PDT 2012


For those that like to debug with printf, a "tee()" method in the chain 
can help:

   list.filter(...)
       .tee(System.out::println)
       .map(...)



On 7/4/2012 1:49 AM, Howard Lovatt wrote:
> Re. Chaining
>
> I personally like the chaining style (particularly with the dots lined
> up). However, I have found it a pain with the Netbeans debugger because
> you can't see the intermediate results. This has often caused me to
> introduce variables for all the steps and to return the final
> array separately (so I can see what is happening).
>
> Any idea if IDEs and the underlying connection to the JVM will be
> updated to support seeing intermediates?
>
> On 4 July 2012 01:13, Brian Goetz <brian.goetz at oracle.com
> <mailto:brian.goetz at oracle.com>> wrote:
>
>      > 1. addAll vs into
>      >
>      > A developer had an interable that he wanted to put all the values
>     from
>      > into a collection.  He tried to use addAll, but it works over a
>      > collection, not an iterable.  He could have used into and flipped
>      > dispatch object with the argument, but it wasn't obvious to do that.
>      > This might be just a case of 'old habits die hard' but it might also
>      > be
>
>     Whatever we do here will change when streams are more Iterator-like and
>     less Iterable-like.  (This is a big theme for the next round of API
>     design, currently in progress in a branch, which should be rolled out
>     hopefully soon.)  Would a Stream.concat(otherStream) method do what you
>     were thinking of?
>
>      > 3.  Some feedback from Martijn:
>      >
>      > I noticed that I happily started using a chaining idiom in my
>     code, e.g.
>      >
>      > return students.filter(student -> student.getAge() > 18).into(new
>      > ArrayList<>());
>      >
>      > Given my lack of recent functional programming expertise, I think
>     this
>      > is a good thing. But I'm a little concerned that the chaining idiom
>      > becomes hard to read for non-functional programmers, some education
>      > might be required.  Perhaps in the educational material, samples are
>      > laid out like so (each 'chained' method is lined up with the method
>      > before it):
>      >
>      > return students.filter(student -> student.getAge() > 18)
>      >                     .into(new ArrayList<>());
>
>     Absolutely.  In all our sample code, we use one method per line, with
>     the dots lining up.  IDEs mostly support this.
>
>      > You might also find Java developers wanting to pull everything back
>      > into a local variable, e.g.:
>      >
>      > List<Student> filteredStudents = new ArrayList<>()
>      > return students.filter(student -> student.getAge() >
>     18).into(filteredStudents);
>
>     This is a common first impulse of Java developers -- give everything a
>     name -- but will probably be overused until people get comfortable with
>     chaining.  A major design goal for these libraries has been to enable
>     getting rid of the "garbage intermediate variables".  The farther
>     between their declaration and use (say, if the chain in the above
>     example were longer), the more problematic the garbage variables become.
>
>      > Another example pulling the Predicate in locally:
>      >
>      > Predicate<Student> isLegal = (Student student) ->
>     student.getAge() > 18;
>      > return students.filter(isLegal).into(new ArrayList<Student>());
>
>     If people want to do this for readability or reuse, that's fine.  (If
>     they think there is any performance benefit to it, they're mistaken;
>     stateless lambda captures are optimized into constant loads.)
>
>      > One other (unecessary?) idiom they might use is assigning back to a
>      > collection that is the result of the filter/reduce/map/whatever,
>     e.g.:
>      >
>      > List<Student> legalStudents = new ArrayList<>();
>      > Predicate<Student> isLegal = (Student student) ->
>     student.getAge() > 18;
>      > legalStudents = students.filter(isLegal).into(legalStudents);
>      > return legalStudents;
>      > // as opposed to
>      > // return students.filter(isLegal).into(legalStudents);
>
>     Right.  These will be hard habits for people to break.
>
>      > 4. Type inference
>      >
>      > IDE or compiler support might be needed to teach developers that Java
>      > is smarter than they think with regards to Type inference.  For
>      > example a refactor to do the following:
>      >
>      > // Predicate<Student> isAdult = (Student student) ->
>     student.getAge() > 18;
>      > // Can be written as:
>      > Predicate<Student> isAdult = student -> student.getAge() > 18;
>      >
>      > Perhaps a -lint option on javac for this kind of thing would be
>      > useful?  I guess it ultimately depends on how the expected idiom for
>      > writing this code works.
>
>     I expect IDEs will auto-suggest for this.
>
>      > 5. Function Composition
>      >
>      > There was a genuine desire from people to have function composition.
>      > This was somewhat driven by people with experience of functional
>      > programming in other languages, but there were still scenarios where
>      > it seemed like the cleanest idiom.  The lack of function types seems
>      > to make it hard to introduce function composition in the general
>     case,
>      > but is there an expectation that composition methods will be provided
>      > for all the functional core library interfaces?
>
>     There is some very limited type-specific composition, such as
>     Mapper.compose or Predicate.{and,or}.  But I suspect whatever we might
>     do in the area of general-purpose composition would be deeply
>     disappointing to functies.  So we're unlikely to do much here.
>
>
>
>
>
>
>
> --
>    -- Howard.
>



More information about the lambda-dev mailing list