<< §2.1 playedBy relation | ↑ Table of Contents ↑ | §2.3 Lifting >> |
§2.2 Lowering
Each instance of a bound role class internally stores a reference to its base object. The reference is guaranteed to exist for each bound role instance, and cannot be changed during its lifetime.
(a) Definition of lowering
Retrieving the base object from a role object is called lowering. No other means exists for accessing the base reference.
(b) Places of lowering
The lowering translation is not meant to be invoked
by client code, but implicit translations are inserted by
the compiler at all places where a role type is provided while the
corresponding base type (or a super type) was expected.
In other words: lowering translations are inserted by the compiler at
all places in a program which would otherwise not be type correct
and which using lowering are statically type correct.
This may concern:
- the right hand side of an assignment wrt. the static type of the left hand side,
- the argument values of a method or constructor call wrt. the static type of the corresponding formal parameter,
- the return value of a method compared to the declared return type of the method.
- a role parameter in a callout binding (§3.3.(d))
- or the return value in a callin binding (§4.5.(d))
1 | public team class MyTeamA { |
2 | public class MyRole playedBy MyBase { ... } |
3 | void useMyBase(MyBase myb) {...} |
4 | MyRole returnMyRole() {...} |
5 | public void doSomething() { |
6 | MyRole r = new MyRole(new MyBase()); |
7 | MyBase b = r; |
8 | useMyBase(r); |
9 | MyBase b2 = returnMyRole(); |
10 | } |
11 | } |
Lowering translations are not inserted for
- reference comparison (using
==
or!=
) instanceof
checks- cast expressions
- return values in callout bindings §3.3.(d))
- parameters in callin bindings (§4.5.(d))
For cases where lowering shall be forced see §2.2.(d) below.
(c) Typing
The static type of an implicit lowering translation is the base class
declared using playedBy
in the respective role class.
(d) Explicit lowering
If a base type is also the super type of its role,
which frequently happens, if a base reference is known only by
the type Object
, lowering cannot be deduced automatically,
since a type could be interpreted both as a role type and a base type.
These cases may need explicit lowering.
For this purpose the role class must declare to implement the interface
ILowerable
(from org.objectteams.ITeam
).
This will cause the compiler to generate a method
public Object lower()
for the given role class. Client code may use this method to explicitly request the base object of a given role object.
1 | public team class MyTeamA { |
2 | public class MyRole implements ILowerable playedBy MyBase { ... } |
3 | public void doSomething() { |
4 | MyRole r = new MyRole(new MyBase()); |
5 | Object oMyRole = r; |
6 | Object oMyBase = r.lower(); |
7 | } |
8 | } |
(e) Lowering of arrays
Lowering also works for arrays of role objects.
In order to lower an array of role objects,
a new array is created and filled with base objects, one for each
role object in the original array. The array may have any number
of dimensions at any shape. The lowered array will have exactly the
same shape.
Note, that each lowering translation will create a new array.
(f) Ambiguous lowering
When assigning a value of a bound role type to a variable or argument of type java.lang.Object
this situation is considered as ambiguous lowering because the assignment could apply either (a) a direct upcast to Object
or (b) lowering and then upcasting.
In such situations the compiler will not insert a lowering translation, but a configurable warning will be issued.
<< §2.1 playedBy relation | ↑ Table of Contents ↑ | §2.3 Lifting >> |
Effects:
An instance of type
MyRole
is lowered to typeMyBase
whenb
(line 7)MyBase
(line 8)MyBase
(line 9)Note: The constructor call in line 6 uses the lifting constructor as defined in §2.4.1