Print Shortlink

Groovy 2.0 and static type checking

A common sentiment echoed by developers of Groovy is that Groovy being a dynamically-typed language, makes them catch the syntax errors on type-safety only during runtime. The answer to that is Test Driven Development. Unfortunately a majority do not use TDD in their projects. Groovy 2.0 has come to their rescue through static type checking. Though, not a great fan of this feature, it may provide some smiles on the developer’s faces.

We have two classes Person.groovy and PersonUser.groovy as shown below. While writing this code we’ll make a couple of silly typos as shown below.

//Person.groovy
class Person{
 String name
 int age
 def eat(){
  "${nme} is eating" //error
 }
}
//PersonUser.groovy
class PersonUser{
 static void main(args){
  def p1 = new Person(name:"Sam",agee:12)//error
  println p1.eat()
 }
}

Running PersonUser.groovy will report error while creating an instance of Person as “agee” is not available. Even if we fix that the p1.eat() statement will throw an exception as we have misspelt name in eat method.
It’ll be better if the Groovy compiler reports these errors during development than waiting for the runtime to report it.

Groovy 2.0 introduces an annotation @groovy.transform.TypeChecked which can be applied on classes or methods. Rewriting the code to use this annotation will report a compile-time error as shown below.

//Person.groovy
@groovy.transform.TypeChecked
class Person{
 String name
 int age
 def eat(){
 "${nme} is eating" //[Static type checking] - The variable [nme] is undeclared
 }
}
//PersonUser.groovy
class PersonUser{
@groovy.transform.TypeChecked
 static void main(args){
  def p1 = new Person(name:"Sam",agee:12)//[Static type checking] - No such property:agee for  Person 
  println p1.eat()
 }
}

The static type checker of groovy reports an error and you’re happy to fix it now in development phase. The problem is adding the @TypeChecked doesn’t seem to cooperate with the dynamic features of Groovy. For example, the following code will work fine without the type checking.

class PersonUser{
 //Uncomment the line below and you'll notice blood bath
 //@groovy.transform.TypeChecked
 static void main(args){
  Person.metaClass.work = {
    "${delegate.name} is working"
  }
  def p1 = new Person(name:"Sam",age:12) 
  println p1.eat()
  println p1.work()
 }
}

Adding the Type checker ruins the party. The same seems to be the case with closures as well. Uncommenting the TypeChecked annotation in Person class will report errors in the closure doSomething.

//@groovy.transform.TypeChecked
class Person{
	String name
	int age
	def eat(){
		"${name} is eating"
	}
	def doSomething = {i->
		i++
	}
}

The static type checker tries to resolve the dynamic features of Groovy and fails.There’re a number of rules where the static type checking works and doesn’t. We need to be aware of them before you use the type checker.

Page 1 of 1

One Response

  1. Tibo

    For dynamic usages, use declared types in the closures:
    e.g.:
    def doSomething = {i -> i++}
    def doSomething = {int i -> i++}

Leave a Reply