§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
}
Effects:

An instance of type MyRole is lowered to type MyBase when

  • assigning it to b (line 7)
  • passing it as argument to a method with formal parameter of type MyBase (line 8)
  • assigning the return value to a variable of type MyBase (line 9)

Note: The constructor call in line 6 uses the lifting constructor as defined in §2.4.1

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.