What's new in Project Lambda this week?
It seems that the Project Lambda developers have conspired to ensure that my blog will always be out of date. I recently wrote about my first impressions from using Project Lambda, based on build b74. Now that I'm writing this, b75 is out and they've renamed the Block
, IntBlock
, DoubleBlock
, and various BiBlock
interfaces to replace the word Block with Consumer. I suppose that's more consistent with Supplier
, since a Consumer
consumes a value and returns nothing, while a Supplier
takes no input and produces something. It also ties in well with the pipeline metaphor they're using for Stream
s (which will still need to wait for a later post, since I got playing with default methods in interfaces this week).
Additionally, they've added several more interfaces to java.util.function
to accommodate Function
s and BiFunction
s that return primitive values (still to avoid the overhead of boxing, presumably). It's interesting to compare these specialized (and specially-named) interfaces to Scala's use of the @specialized
annotation (discussed, here, for example) to avoid the same problem.
Pimping Collections
I'm horribly abusing a term that has grown popular in the Scala community for the case where you appear to add functionality to an existing type by providing an implicit view that converts objects of the existing type to objects of the enhanced type. This is referred to as the pimp my library pattern (going back several years, including by Prof. Odersky here). What I'm doing here isn't implicit, but it does show a way that we can use interfaces with default methods to layer functionality onto library types with relatively little ceremony.
In some of my previous posts, (like this one and especially this one), I talked about some nice higher-order functions on collections that most functional programming language environments provide as part of their standard library. The fact is that most of these higher-order functions can be implemented in terms of iterating through elements. Since Java 1.5, the standard collections (except Map
and its implementations) all implement the Iterable
interface. Wouldn't it be great if we could add these higher-order functions as methods on existing collection types? We can't really do that (without compiling our own version of the standard library), but we can inject the iterator
method from the builtin types as a lambda to construct a type that does have this functionality.
Yo dawg, I herd you like iterators
Let's extend the Iterable
interface with an AugmentedIterable
interface that defines additional functionality based on the iterator
method:
As you can see, many of the methods return a new AugmentedIterable
whose iterator
method (defined by a lambda) delegates to the iterator
method of the original AugmentedIterable
. I put an iterator in your iterator, so you can iterate while you iterate.
Note that this implementation with delegated iterators has the side-effect of making most of these methods lazy (except toList
and foldLeft
, which don't produce new AugmentedIterable
s).
Let's add a quick utility method to construct an AugmentedIterable
from an existing Iterable
, and test our methods:
Conclusions
This still isn't quite as nice as the "pimp my library" pattern, as we still need either the explicit call to augment
to convert our Collection
into an AugmentedIterable
. Furthermore, I didn't really need an interface with default methods to do this, as I believe I could have made AugmentedIterable
an abstract class. Where things get interesting is that we could add more functionality derived from Iterable
in another interface and then mix them together in a new interface that inherits from both. Alternatively, I could create new collection types that extend the built-in types but also add the AugmentedIterable
behaviour:
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.