London Lambdas Hackday: Existing Code

Brian Goetz brian.goetz at oracle.com
Tue Jul 3 08:28:09 PDT 2012


> One of the projects we tried to lambda-ize was vert.x.  This is
> essentially an asynchronous eventing system (similar to node.js) on
> the JVM.  This was a big success in the sense that because everything
> was based upon callbacks to a handler interface, it was incredibly
> straightforward to lambda-ize and it made code both easier to read and
> shorter.  Unfortunately it was really too easy - we didn't really
> learn that much from this exercise.

Well, we learned one thing -- that easy examples just work.  That's 
something.

> My only comment building on this is that variable scoping makes
> converting anonymous inner classes more difficult than absolutely
> necessary. The context to this was a programmer converting anonymous
> inner classes in some existing code to lambdas in order to remove
> boilerplate.  Due to the fact that the inner function had a variable
> with the same name as a variable that had been defined in the outer
> method, he received a “error: variable num is already defined in
> method” message.

This is one of those things that is still under discussion.  The "no 
shadowing" rule comes from a motivation that lambdas are more like 
ordinary blocks of code (like the body of an 'if') than like inner 
classes, and shadowing is prohibited in those contexts.  But we're not 
sure if this helps or hurts.

> This example spurned some interesting discussion:
>
> 1. Guava’s predicates vs Java 8 Predicates
>
> People using Guava's predicate library already will have an interface
> doing something identical to the Java 8 Predicate.  Furthermore they
> will be able to

to?

> 3. Method References
>
> If you heavily use guava's FP constructs then there's an expectation
> of needing some kind of Function<Foo,Bar>.  In other words if you're
> using a method reference SomeClass::someMethod, then you expect
> someMethod to be of type, "Function<Foo,Bar> someMethod()" rather than
> "Foo someMethod(Bar bar)".  From talking to people, it actually seems
> like method references are more natural if they're not coming from a
> guava background.  This isn't just guava - there are several libraries
> offering a limited range of FP Oriented facilities.  Not sure what can
> be done about this, but perhaps this is another thing that could be
> helped with documentation and examples, rather than needing a
> language/API change.

Absolutely.  Method references are the hidden gem of this whole 
exercise, but will take some time (and IDE help!) for people to realize 
their effectiveness.

> On a related note, it was initially hard to understand where you got a
> method reference from.  I suspect that this is something that
> programmers need to just develop a sense for, but there certainly was
> confusion about static and instance method references.  Some people
> tried to use SomeClass::someMethod instead of someInstance::someMethod
> when getting obtaining references.  At a conceptual level it seems
> obvious if you're referring to an instance method it needs to be
> associated with some instance, but there is something confusing about
> this.

Actually, its more complicated than that.  You can take a method 
reference to an instance method in two ways, bound and unbound.  Both 
are useful; I think the unbound form is probably more useful.  For class 
C, if you have an instance method foo of type T->U, then

   C::foo

is of type (C, T) -> U and

   instanceOfC::foo

is of type T -> U.

The unbound form shows up in "map" a lot:

       people.filter(Person::isTall)
             .map(Person::getHeight)
             .into(tallPeopleHeights);

Here, the instance is provided by the stream.

> 4. Factory naming conventions don't make sense anymore
>
> If you care about API Fluency then you might frequently have factory
> methods that are named in that style, for example:
>
> LocalDate eventDate = LocalDate.from(eventTimestamp)
>
> And "LocalDate from eventTimestamp" reads like an English sentence.
> However when you start to use a factory method as a method reference,
> the naming convention is totally lost.

Good point.  In this case, maybe better to just use a lambda for 
readability:

   timestamps.map(t -> LocalDate.from(t))
             .into(...)



More information about the lambda-dev mailing list