Groovy – using parameters with default values to separate method configuration from method body

November 23, 2012 at 10:37

And with that huge title 😀 , I want to talk about a little technique that I like to use in Groovy by taking advantage of the method parameters with default values feature. By method configuration and method body I am refering to two typical parts of a business logic method (for example, a method of a Grails service) that you have probably seen a lot. Imagine a method like the following:

def updateContractAddress(contract, newAddress) 
{
   // Method configuration
   def client = contract.client
   def country =  CountryService.findByPostalCode(newAddress.postalCode)
   def currentAddress = client.address

   // Method body
   client.previousAddresses << currentAddress
   client.address = new Address
   client.save()
}

As you can see, the method has two different parts:

  • In the first one, we just configure some variables that we will use in order to clean up our code, or may to not calling the same method twice (as would happen, for example, with the implicit method Contract.getClient(), that would be called three times in the variable client was inlined).
  • In the second one, the actual method business logic is performed.

This is actually the method implementation, the previous stuff is just boiler plate code. In fact, in Java I have seen a lot the pattern of separating the previous code in multiple methods, in order to separate this two parts:

def updateContractAddress(contract, newAddress) 
{
   def client = contract.client
   def country =  CountryService.findByPostalCode(newAddress.postalCode)
   def currentAddress = client.address
   updateContractAddress(contract, newAddress, client, country, currentAddress)
}

private updateContractAddress(contract, newAddress, client, country, currentAddress) 
{
   client.previousAddresses << currentAddress
   client.address = new Address
   client.save()
}

Not bad. As I always say when joking, almost every life problem can be solved by applying an extract to method refactoring (yes, I am a funny guy 😆 ). But in Groovy we have another alternative that I find to be more elegant and easy to read.

As you know (and if don't, you should read this 🙂 ), Groovy supports default values for a method arguments. So, you can do the following:

def method(a, b = 3, c = []) { ... } 

That is the same as doing:

def method(a) { method(a, 3, [] }
def method(a,b) { method(a, b, [] }
def method(a,b,c) { ... }

In fact, I think this is what the compiler actually do, making the feature a simple code generator that takes place in preprocessing time (but that is just me guessing 🙂 ). Anyway, what you may not know is that the optional parameters can be assigned with method calls, and that this method calls can use the rest of the parameteres. So, the original code can be as following:

def updateContractAddress(contract, newAddress, client = contract.client, 
      currentAddress = client.address, country =  CountryService.findByPostalCode(newAddress.postalCode))
{
   client.previousAddresses << currentAddress
   client.address = new Address
   client.save()
}

Now we can focus on the method body without being distracted by all this boilerplate code, but if we want to take a look at it, is just a few lines above, and we don't need to navigate the class as the previous solution. And for free, we obtain a parametrized method: in we need to pass the client as a parameter in the future, we can do it without modifying a single line 🙂 .

What I love about this trick is that it can aslo be used with Closures, so you can do stuff like the following:

[ name: 'diego', lastName: 'toharia', country: 'spain' ].each { 
   factName, factValue, capitalizedFactValue = factValue.capitalize() ->
   person[factName] = capitalizedFactValue
}

Ha 😀 . Love it.

Bonus track

When using this last trick, be careful: if the method that receives your closure checks the number of arguments it receives in order to invoke it with the proper number of arguments, you can see how your method initialization is replaced by an unexpected value! An example of this would be the closure passed to a Grails validator:

class SomeDomainClass {
   String prop
   static constraints = {
      prop(nullable: true, validator: { prop, domainClass, propIsEmpty = prop.trim() != "" -> 
         propIsEmpty || validateProp(prop)
      }
   }
}

In this example, the custom validator for the property prop init the propIsEmpty parameter in the closure signature, but Grails is smarter: if you pass a closure with one argument, it invokes it with the property. If it can receives two arguments, it passes the property and the object. But if the closure declare three arguments, it passes the current validation errors as well, so you will find that propIsEmpty won't have what you expected 😀 . So use it carefully 🙂 .