Details
-
Improvement
-
Status: Closed
-
Major
-
Resolution: Fixed
-
2.3.7
Description
Sometimes it is necessary to express that a trait can only be applied to a class which either implements some interface or is a direct subclass of something else. While in the case of an interface, it is possible to make the trait implement the interface, it forces the trait to expose the methods from the interface although this interface maybe only considered as a dependency, not a strong contract.
In the case of a class, the situation is even more complex, because a trait cannot extend a class. A dynamic trait may solve the issue by not having an explicit contract, that is to say that just calling the method is enough, but as long as @CompileStatic is used, compilation will fail.
We suggest to add the @SelfType annotation to cover those cases, like in the following example:
import groovy.transform.SelfType import groovy.transform.CompileStatic trait A { int a() { 1 } } @CompileStatic @SelfType(A) trait B { int b() { 2*a() } } class C implements A,B {} def c = new C() assert c.b() == 2
Here, compilation of the B trait will succeed because we declared A as a self type.
If a class implementing the trait doesn't satisfy the self type constraints, then compilation should fail.
It should be possible to define multiple self types.