§2.1.2.(e) No free type parameters

Neither the role class nor the base class in a playedBy binding must have any free type parameters. If both classes are specified with a type parameter of the same name, both parameters are identified and are not considered as free.

From this follows that a role class cannot have more type parameters than its base. Conversely, only one situation exists where a base class can have more type parameters than a role class bound to it: if the role class has no type parameters a generic base class can be bound using the base class's raw type, i.e., without specifying type arguments.

Note:
The information from the playedBy declaration is used at run-time to associate role instances to base instances. Specifying a base class with free type parameters would imply that only such base instances are decorated by a role whose type is conform to the specified parameterized class. However, type arguments are not available at run-time, thus the run-time environment is not able to decide which base instances should have a role and which should not. This is due to the design of generics in Java which are realized by erasure.

The following example shows how generics can be used in various positions. Note, that some of the concepts used in the example will be explained in later sections.

1
public class ValueTrafo<T> {
2
  public T transform(T val) throws Exception { /* ... */ }
3
}
4
public team class TransformTeam {
5
    protected class SafeTrafo<U> playedBy ValueTrafo<U> {
6
        U transform(U v) -> U transform(U val); 
7
        protected U safeTransform(U v) {
8
            try {
9
            	return transform(v);
10
            } catch (Exception e) {
11
            	return v;
12
            }
13
        }
14
    }
15
    <V> V perform(ValueTrafo<V> as SafeTrafo<V> trafo, V value) {
16
        return trafo.safeTransform(value);
17
    } 
18
}
19
...
20
ValueTrafo<String> trafo = new ValueTrafo<String>();
21
TransformTeam safeTrafo = new TransformTeam();
22
String s = safeTrafo.perform(trafo, "Testing");
23
Explanation
  • Line 5 shows a role with type parameter U where the type parameter is identified with the corresponding type parameter of the role's base class (which is originally declared as T in line 1.
  • Line 6 shows a callout binding (§3) which mappes a base method to a corresponding role method while maintaining the flexible typing.
  • The regular method in lines 7-13 just passes values of type U around.
  • The generic method in line 15 ff. uses declared lifting (§2.3.2) to obtain a role for a given base object. The method has no knowledge about the concrete type arguments of either role nor base, but works under the guarantee that both type arguments will be the same for any single invocation.
  • Lines 20 ff. finally create instances of base and team and invoke the behavior thereby instantiating type parameters to String.