<< §4.2 Callin modifiers (before, after, replace) | ↑ Table of Contents ↑ | §4.4 Callin parameter mapping >> |
§4.3 Base calls
Role methods with a callin
modifier should contain
a base call which uses the special name base
in order to invoke the original base method (original means: before replacement).
(a) Syntax
The syntax for base calls is base.m()
,
which is in analogy to super calls.
A base.m()
call must use the same name and signature
as the enclosing method. This again follows the rule, that roles
should never explicitly use base names, except in binding declarations.
(b) Missing base call
For each callin method, the compiler uses some flow analysis to check whether
a base call will be invoked on each path of execution (analysis is very similar
to the analysis for definite assignment regarding final variables -
JLS §16).
The compiler will issue a warning if a base call is missing either
on each path (definitely missing) or on some paths (potentially missing).
Instead of directly invoking a base call, a callin method may also call
its explicit or implicit super version using super.m()
or tsuper.m()
(see §1.3.1.(f)).
In this case the flow analysis will transitively include the called super/tsuper version.
(c) Duplicate base call
If a callin method contains several base calls, the compiler gives a warning if this will result in duplicate base call invocations on all paths (definitely duplicate) or on some paths (potentially duplicate). Again super/tsuper calls are included in the flow analysis (see 4.3(b)).
(d) Parameter tunneling
If a base method has more parameters
than a callin method to which it is composed, additional
parameters are implicitly passed unchanged from the original
call to the base call (original means: before interception).
I.e., a call base.m()
may invisibly pass additional
parameters that were provided by the caller, but are hidden from the
role method.
(e) Fragile callin binding
If a role method returns void, but the bound base method declares a non-void result, this is reported as a fragile callin binding: The result can still be provided by the base call, but omitting the base call may cause problems depending on the return type:
- For reference return types
null
will be returned in this case. - In the case of primitive return types this will cause a
ResultNotProvidedException
at run-time.
It is an error if a callin method involved in a fragile callin binding has definitely no base call.
(f) Base super calls
If a callin method rm
is bound to a base method B1.m
that in turn overrides an inherited method B0.m
(B0
is a super class of B1
),
the callin method may use a special form of a base call denoted as
base.super.rm();
Such base super call invokes the super method of the bound base method,
here B0.m
. This invocation is not affected by any further callin binding.
A base super call bypasses both the original method B1.m
and
also other callin bindings that would be triggered by a regular base call.
For this reason any application of this construct is flagged by a decapsulation warning
(see §3.4).
Comment:
Base calls can occur in callin methods that are not yet bound. These methods have no idea of the names of base methods that a sub-role will bind to them. Also multiple base methods may be bound to the same callin method. Hence the use of the role method's own name and signature. The language implementation translates the method name and signature back to the base method that has originally been invoked.Example code (Base Call):
1 | public class ValidatorRole playedBy Point { |
2 | callin void checkCoordinate(int value) { |
3 | if (value < 0) |
4 | base.checkCoordinate(-value); |
5 | else |
6 | base.checkCoordinate(value); |
7 | } |
8 | checkCoordinate <- replace setX, setY; |
9 | } |
<< §4.2 Callin modifiers (before, after, replace) | ↑ Table of Contents ↑ | §4.4 Callin parameter mapping >> |
Effects:
Point
(see line 8).