In a recent post, I was talking about a micro DSL to create a simple “find x in a list” service. The key thing here is that it defines how to look for x in the list. So the list can be a list of anything, not just a list of x’s.
Just to recap then, to find something in a list, the original client code (using a static import) looks like this.
|
The class (in this case NeedleFinder
) implements the DSL and specifically decides in the in
method how to compare a Needle
object to whatever is in the haystack list. I wanted to create a more generic class so started to implement the ListFinder
to use generics and a couple of interesting things came out.
The generified class looks like this.
|
With the following test case showing its usage (the Needle
and Bale
class aren’t show for brevity).
|
Equality
Here we’re defining the equality of a Needle
in a list of Bale
objects to be when the name of a Needle
is contained in the name of the Bale
. A silly example I know but it illustrates that we redefine what we mean by equality for the list finder by implementing the ListFinder.Comparator
. The concrete example that spawned the idea was when searching for a Race
object inside a list of Event
objects; two completely different entities.
Type inference over too many types
Anyway, what I thought was interesting about this example was the type inference going on in the static find method. I originally wanted to just use ListFinder.find
method directly as in the following.
|
Where ListFinder
is statically imported. Usually, I’d rely on type inference here to work out that needle means T
and therefore T
is of type Needle
. However, in the case above, the compiler will complain as the haystack parameter is not of type Object
. The trick is that the generic method find
in ListFinder
needs to infer two types (T
and L
) but only has enough information for T
. So it defaults L
to type Object
.
The alternative is to use the full notation as follows.
|
Or (as I’ve done in the test) use an internal method who’s return type gives the compiler enough information to infer both types. I prefer this approach as it makes the DSL expression to find a needle much more readable.
Summary
So, Java can’t chain methods to infer the types. I didn’t really expect it to be able to so, its a bit much to ask for. Although it would be pretty sweet if it could.
One last thing, Ray Barlow was showing me a Jedi alternative to the finder. If we’re lucky, he might blog about it. It seems Jedi offers some measure of residence against the proliferation of anonymous inner classes in lieu of closures but in all honestly, I just wanted to get in some big words in before signing off. TTFN.
Recommended Reading
- Domain Specific Languages (Addison-Wesley Signature), Martin Fowler
- DSLs in Action, DSLs in Action
- The Definitive ANTLR 4 Reference: Building Domain-Specific Languages (Pragmatic Programmers), Terence Parr