§4.9.3.(c) Covariant replace binding
When using the syntax of §4.9.3.(b) to capture base methods with
covariant return types in a callin binding with the replace
modifier,
the role method must be specified using a free type parameter as follows:
<E extends RT> E rm() <- replace RT+ bm();
The role method rm
referenced by this callin binding must use the same style
of return type using a type parameter.
The only possible non-null value of type E
to be returned from such method is the value provided by a base-call or a tsuper-call.
This rule enforces the constraint (2) above.
Note that this rule is further generalized in §4.10.
Binding a parametric role method
1 |
public class SuperBase { |
2 |
SuperBase foo() { return this; } |
3 |
void check() { System.out.print("OK"); } |
4 |
} |
5 |
public class SubBase extends SuperBase { |
6 |
@Override |
7 |
SubBase foo() { return this; } |
8 |
void print() { System.out.print("SubBase"); } |
9 |
String test() { |
10 |
this.foo().print(); |
11 |
} |
12 |
} |
13 |
|
14 |
public team class MyTeam { |
15 |
protected class R playedBy SuperBase { |
16 |
callin <E extends SuperBase> E ci() { |
17 |
E result= base.ci(); |
18 |
result.check(); |
19 |
return result; |
20 |
} |
21 |
<E extends SuperBase> E ci() <- replace SuperBase+ foo(); |
22 |
} |
23 |
} |
Explanation:
SubBase.foo
in line 7 redefines the return type fromSuperBase
(inherited version) toSubBase
, thus clients like the method call in line 10 must be safe to assume that the return value will always conform toSubBase
.foo
by specifyingSuperBase+
as the expected return type. Thus, if an instance ofMyTeam
is active at the method call in line 10, this call tofoo
will indeed be intercepted even though this call is statically known to return a value of typeSubBase
.E
. Since the base call is known to have the exact same signature as its enclosing method, the value provided by the base call is of the same typeE
and thus can be safely returned fromci
. Note, that no other non-null value is known to have the typeE
.SuperBase
as an upper bound for the typeE
the callin methodci
may invoke any method declared in typeSuperBase
on any value of typeE
. For an example see the call tocheck
in line 18.As an aside note that the above example uses type
SuperBase
in an undisciplined way: within roleR
this type is bound usingplayedBy
and the same type is also used directly (as the upper bound forE
). This is considered bad style and it is prohibited ifSuperBase
is imported using an base import (§2.1.2.(d)). Here this rule is neglegted just for the purpose of keeping the example small.