§2.3.2 Declared lifting

(a) Parameters with declared lifting

A non-static team-level method or constructor may declare a parameter with two types in order to explicitly denote a place of lifting. Using the syntax

public void m (BaseClass as RoleClass param) { stmts }

a liftable parameter can be declared, provided the second type (RoleClass) is a role of (playedBy) the first type (BaseClass). Furthermore, the role type must be a role of the enclosing team class defining the given method. The role type must be given by its simple (i.e., unqualified) name.
Such a signature requires the caller to provide a base object (here BaseClass), but the callee receives a role object (here RoleClass). In fact, the client sees a signature in which the "as RoleClass" part is omitted.
Compatibility between caller and callee sides is achieved by an implicitly inserted lifting translation. A signature using declared lifting is only valid, if the requested lifting is possible (see §2.3.3 and §2.3.4 for details).

(b) Super in the context of declared lifting

Calling super or tsuper in a method or constructor which declares lifting for one or more parameters refers to a method or constructor with role type parameters, i.e., lifting takes place before super invocation. Nevertheless, the super method may also have a declared lifting signature. It will then see the same role instance(s) as the current method.

(c) Declared lifting of arrays

If a parameter involving explicit lifting should be of an array type, the syntax is

public void m (BaseClass as RoleClass param[]) ...

Here the brackets denoting the array apply to both types, BaseClass and RoleClass.

(d) Declared lifting for catch blocks

Also the argument of a catch block may apply declared lifting like in:

catch (BaseException as RoleClass param) { stmts }

This syntax is only valid in a non-static scope of a team (directly or nested). In the given example, RoleClass must be played by BaseException. Note, that RoleClass itself need not be a throwable. As the effect of this declaration the catch block will catch any exception of type BaseException and provides it wrapped with a RoleClass instance to the subsequent block.
Also note, that re-throwing the given instance param has the semantics of implicitly lowering the role to its base exception before throwing, because the role conforms to the required type Throwable only via lowering.

(e) Generic declared lifting

A method with declared lifting may introduce a type parameter that is bounded relative to a given role type. Such bound is declared as:

<AnyBase base SuperRole>
void teamMethod(AnyBase as SuperRole arg) {
   // body using arg as of type SuperRole
}

This means that AnyBase is a type parameter whose instantiations must all be liftable to role SuperRole.

The given type bound requires the call site to supply an argument that is compatible to any base class for which the current team contains a bound role that is a sub class of SuperRole, including SuperRole itself. However, SuperRole itself need not be bound to any base class. On the other hand, different valid substitutions for AnyBase need not be related by inheritance.

Note:
This feature supports generalized treatment of otherwise unrelated base classes. This is done by defining one bound role for each base under consideration and by having all these roles extend a common unbound role.
Example code (Declared Lifting):
1
team class Super {
2
  public class MyRole playedBy MyBase { ... }
3
  void m (MyRole o) { ... };
4
}
5
team class Sub extends Super {
6
  void m (MyBase as MyRole o) {
7
    // inside this method o is of type MyRole
8
    super.m(o);
9
  }
10
}
11
Sub s_team = new Sub();
12
MyBase b = new MyBase();
13
s_team.m(b); // clients see a parameter "MyBase o"
Effects:
  • Clients use method m with a base instance (type MyBase) as its argument (line 13).
  • Before executing the body of m, the argument is lifted such that the method body receives the argument as of type MyRole (line 8).