§4.8 Callin precedence

If multiple callins from the same team refer to the same base method and also have the same callin modifier (before, after or replace), the order in which the callin bindings shall be triggered has to be declared using a precedence declaration.

(a) Precedence declaration

A precedence declaration consists of the keyword precedence followed by a list of names referring to callin bindings (see §4.1.(e) for named callin bindings).

precedence callinBinding1, callinBinding2;

A precedence declaration is only legal within a role or team class.
The order of elements in a precedence declaration determines their priority during dispatch, similar to priorities based on activation of several team instances (§5.1). This means that before and replace binding with highest priority trigger first, whereas after bindings with highest priority trigger last. For binding precedences (as opposed to class based precedence, see §4.8.(c) below) which refer to after bindings, the precedence declaration must also use the after keyword to remind the programmer that the execution order is inverse to the textual order.

precedence after importantExecuteLast, lessImportantExecuteEarlier;

(b) Qualified and unqualified names

Within a role class a callin binding may be referenced by its unqualified name. A precedence declaration in a team class must qualify the callin name with the name of the declaring role class. A team with nested teams may concat role class names. Elements of a qualified callin name are separated by ".".
The callin binding must be found in the role specified by the qualifying prefix or in the enclosing role for unqualified names, or any super class of this role (including implicit super classes §1.3.1).

(c) Class based precedence

At the team level a precedence declaration may contain role class names without explicitly mentioning callin bindings in order to refer to all callin bindings of the role.

(d) Multiple precedence statements

All precedence statements are collected at the outer-most team. At that level all precedence declarations involving the same base method are merged using the C3 algorithm [3]. When merging precendence declarations more deeply nested declarations have higher priority than outer declarations. For several declarations at the same nesting level the lexical ordering determines the priority.

At any point the C3 algorithm will ensure that the resulting order after merging is consistent with each individual precedence declaration. It is an error to declare incompatible precedence lists that cannot be merged by the C3 algorithm.

(e) Binding overriding

Precedence declarations may conflict with overriding of callin bindings (see §4.1.(e)): For each pair of callin bindings of which one callin binding overrides the other one, precedence declarations are not applicable, since dynamic binding will already select exactly one callin binding.
It is an error to explicitly mention such a pair of overriding callin bindings in a precedence declaration.
When a class-based precedence declaration implicitly refers to a callin binding that is overridden by, or overrides any other callin binding within the same precedence declaration, this does not affect the fact, that the most specific callin binding overrides less specific ones.

Callin binding example
1
public class LogLogin playedBy Database {
2
  callin void log (String what) {
3
    System.out.println("enter " + what);
4
    base.log(what.toLowerCase());
5
    System.out.println("leave " + what);
6
  }
7
  void log(String what) <- replace void login(String uid, String passwd) 
8
    with { what <- uid }
9
}
10
(new Database()).login("Admin", "Passwd");
Effects:

Provided the callin bindings are active (cf. §5) then:

  • the call in line 10 is intercepted by method log of role LogLogin.
  • the call target of log is a role of type LogLogin which is created by lifting the original call target (of type Database) to LogLogin.
  • only parameter uid is passed to log (bound to formal parameter what).
  • within method log the base call (line 4) invokes the original method passing a modified uid (converted to lower case, cf. line 4) and the unmodified password, which is hidden from the callin method due to the parameter mapping in line 8.