London Lambdas Hackday: Developer Practices

François Sarradin fsarradin at gmail.com
Wed Jul 4 01:04:33 PDT 2012


Oops! There might be a drawback with solution 2: once you try to debug what
is supposed to be lazily evaluate, you risk to get it eagerly and then lose
data for the rest of the chaining.

Francois
 Le 4 juil. 2012 08:35, "François Sarradin" <fsarradin at gmail.com> a écrit :

> Howard,
>
> Debugging method/function chaining is a recurrent problem in functional
> programming. In a sense, the way you use chaining in FP should help you to
> have a better understanding of the code. But it is not always the case.
>
> Nevertheless, you can use two workarounds in this situation. 1/ As Brian
> said, insert a print call in the chaining, but you need the tee method and
> you cannot use this with a debugger. 2/ You can put part of the chaining in
> a variable and continue the rest of the chaining from this variable. Like
> this:
>
> Iterable<Whatever> iter = myList.a().b();
> iter.c().d();
>
> In this case, you have to transform the code to observe it in a debugger.
> This is only possible if you have a write access to the code.
>
> I think there is a third possibility. But I have to introduce monads ;)
> And even with Java 8, it is hard to use them.
>
> Francois
>  Le 4 juil. 2012 07:50, "Howard Lovatt" <howard.lovatt at gmail.com> a
> écrit :
>
>> 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> 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