Groovy mixed typing

1.6k Views Asked by At

I see that as of Groovy 2.0 there is the possibility to add a TypeChecked annotation to classes or methods to trigger the optional static checking.

I must admit that I am confused by how such a thing could work. The article gives simple examples such as

@TypeChecked
Date test() {
    // compilation error:
    // cannot assign value of Date 
    // to variable of type int
    int object = new Date()

    String[] letters = ['a', 'b', 'c']
    // compilation error:
    // cannot assign value of type String 
    // to variable of type Date
    Date aDateVariable = letters[0]

    // compilation error:
    // cannot return value of type String 
    // on method returning type Date
    return "today"
}

In this case it is clear that some checks will fail. But in the general case, one will use, say, the return value of method A, that is not type checked, inside the type checked method B. In this case I do not see how the compiler can figure out whether method B types are consistent, since it does not have enough information on the return value of method A.

How can one enable type checking on a subset of the code without losing type safety in general?

EDIT

I try to make an example. What if I have an old class

class Old {
  public getFoo() {
    return 1
  }
}

and try to use it from type-checked code, like

@TypeChecked
class New {
  int doubleFoo() {
    return 2 * (new Old().foo)
  }
}

The compiler just does not know what to do, and I guess it will fail to compile (I do not have Groovy2 installed here at work to check). But if this is the case, it become an issue to use any code written before Groovy2. So I imagine something more sophisticated is done, but I am not sure what.

1

There are 1 best solutions below

5
On

There is no such problem. If you call a method from an unchecked class, then it's the declared return type which is used and the behaviour is exactly the same as if you use a Java method from Groovy.

Take the following example:

class A {
   int foo() { 1 }
}

@TypeChecked
class B {
   void bar() {
       int x = new A().foo() // uses the type from A.foo, correct
   }
}

Now, imagine this:

class A {
   Date foo() { new Date() }
}

@TypeChecked
class B {
   void bar() {
       int x = new A().foo() // uses the type from A.foo, foo returns a Date, the compiler throws an error
   }
}

Note that in general, you use mixed type checking in a single class if you have code which heavily relies on dynamic code that the type checker obviously cannot check. This is the case, for example, if you rely on a builder. If so, then you just declare a method which uses the builder as not checked, and the rest of your code is checked. As long as the unchecked method returns a compatible type, type safety is guaranteed.