From named-parameters to Domain-Specific Languages
There have always been a few irritating things to me in Java. However, working on Groovy made me go beyond these limitations, or all the useless boiler-plate code one has to write. If I had to ask for some new features in Java 7, that would certainly be:
- have closure support (or delegate or whatever you call that)
- native syntax for common data structures like lists and maps
- named parameters
Today, I’m going to say a few words about the last item on my list: named parameters.
A few days ago, I read Patrick who was speaking about var args and Java’s lack of named parameters. It also remind me about Paul’s ideas regarding improvements we could bring to Java. I’m definitely on the same wave-length on those Java wishes.
Regarding named-parameters, despite living on the JVM (and hence its limitations), Groovy decided to provide a simple solution for passing named parameters to methods: we’re leveraging the native syntax for Maps and the omition of square brackets. So in Groovy, when you define a map, you can use that native syntax:
def myMap = [aKey: 1, anotherKey: 2, lastKey: 3]
This is quite convenient. But we went a bit further, because when we pass a map as a method argument, we can omit the brackets, so in the end, you can make method calls look like:
myAccount.debit(amount: 500, currency: "euro")
monster.move(x: 400, y: 300, z: 200)
As Groovy allows you to add methods to all classes, you’d probably better add some more readable amounts, like with:
500.euros
200.dollars
So the debit() method could look like that, without named parameters and parentheses:
myAccound.debit 500.euros
And we’re getting closer to Domain-Specific Languages. Operator overloading would also help making the intent potentially clearer:
myAccound + 500.euros
myAccound - 200.dollars
myAccount << 500.euros
myACcount >> 500.euros
I guess method calls are often clearer to read though
Back to DSLs, with named-parameter, closures, operator overloading, if I take again my bank account example again, we could imagine money transactions like that:
def someMoney = 500.euros
InTransaction.do {
accOne.credit( amount: someMoney )
accTwo.debit( amount: someMoney )
}
Or to symbolize the money transfer between accounts:
InTransaction.do { accOne << 500.euros << accTwo }
Again on named-parameters, Patrick was mentioning DAO finder methods. They could advantageously be replaced with:
dao.findBy(name: "Harry", lastName: "Potter")
dao.findAllBy(author: "Rowling")
Grails even goes further with finder methods by intercepting imaginary method calls that translate into queries:
def results = Book.findByTitle("The Stand")
results = Book.findByTitleLike("Harry Pot%")
results = Book.findByReleaseDateBetween( firstDate, secondDate )
results = Book.findByReleaseDateGreaterThan( someDate )
results = Book.findByTitleLikeOrReleaseDateLessThan( "%Something%", someDate )
Be careful to those who don’t like long method names! But of course, there are other solutions for doing queries.