London Lambdas Hackday: Developer Practices
François Sarradin
fsarradin at gmail.com
Tue Jul 3 23:35:00 PDT 2012
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