§3.2 Callout parameter mapping

(a) with clause

If the method designators in a callout binding are signatures (not just method names), parameters and return value may be mapped by a with{...} sub-clause. Parameter mappings may only occur if the enclosing role is a class, not an interface.

(b) Mapping one parameter

For each parameter of the provided base method, exactly one parameter mapping defines, which value will actually be passed to the base method. Callout parameter mappings have this form:

expression -> base_method_parameter_name

(c) Result mapping

The return value of a callout method may be provided by a result mapping:

result <- expression

The right hand side expression of a result mapping may use the special identifier result to refer to the value returned by the base method.
In a method binding with parameter mappings, it is an error to use result as the name of a regular method argument.

Example code (Callout Parameter Mapping):
1
Integer absoluteValue(Integer integer) -> int abs(int i) with {
2
  integer.intValue() -> i,
3
  result <- new Integer(result)
4
}

(d) Visible names

Each identifier that appears within the expressions of a parameter mapping must be either:

  • a feature visible in the scope of the role instance.
  • a parameter of the role method (for parameter mappings).
  • the special name result (for result mappings).
  • in a result mapping also the special name base can be used in order to refer to the bound base instance (provided the method being bound is not static).

The names of base method arguments (i.e., names after mapping) are only legal in the position given in §3.2.(b).

(e) Implicit parameter mappings

If parameter mappings should be omitted the following conditions must hold:

  1. each method parameter of the role method must conform to the corresponding parameter of the base method, and
  2. the result type of the base method must conform to the result type of the role method.

Here conformance includes translation polymorphism (cf. §3.3.(d)).
Parameter correspondence without parameter mapping is determined by declaration order not by names.
Two adjustments can, however, be performed implicitly:

  • If the role method has more parameters than the base method, unused trailing parameters may be silently ignored.
  • If the role method returns void, any result from the base method may be silently ignored.
Example code (Callout with Parameter Mapping):
1
public team class MyTeamA {
2
  public abstract class Role1 {
3
    abstract void payEuro(float euro);
4
    abstract float earnEuro();
5
    void idle(int seconds) { /* do nothing */ };
6
  }
7
  Role1 boss, worker = // initialization omitted
8
  public void transaction () {
9
    boss.payEuro(worker.earnEuro());
10
    boss.idle(123);
11
  }
12
}
13
public class Staff { // a base class 
14
  public void payDM (float dm) { … };
15
  public float earnDM () { … };
16
  public int doze() { … };
17
  // other methods omitted
18
}
19
public team class MySubTeam extends MyTeamA {
20
  public class Role1 playedBy Staff {
21
    void payEuro(float euro) -> void payDM(float dm) with {
22
      euro * 1.95583f -> dm
23
    }
24
    float earnEuro() -> float earnDM () with {
25
      result <- result / 1.95583f
26
    }
27
    idle => doze; // override existing implementation of idle()
28
  }
29
  void doit() {
30
    transaction();
31
  }
32
}
Effects:
  • Class MyTeamA is declaratively complete and can be type checked because it only uses methods that are visible or declared within this context. MyTeamA.Role1 can, however, not be instantiated, because it is abstract.
  • Line 30 has the normal effect of invoking transaction.
  • When executing transaction, the call of worker.earnEuro() is forwarded to the corresponding base object using method earnDM() (binding declaration in line 24). The result is converted by "result / 1.95583f" (line 25).
  • Within the same execution of transaction, the call of boss.payEuro() is forwarded to the corresponding base object using method payDM() (binding declaration in line 21). The parameter euro is converted by "euro * 1.95583f" (line 22).
  • Method idle is forwarded to doze without any parameter mapping. This requires doze to have a signature that is conformable to the signature of idle. In this case a role parameter and a base result are ignored.
    Using the => operator, this binding overrides the existing implementation of idle.