§3.1 Callout method binding

A role class may acquire the implementation for any of its (expected) methods by declaring a callout binding.

(a) Prerequisite: Class binding

A callout binding requires the enclosing class to be a role class bound to a base class according to §2.1. However, callout bindings are not allowed if the role is involved in base class circularity (see §2.1.2.(b)).

(b) Definition

A callout binding maps an abstract role method ("expected method") to a concrete base method ("provided method"). It may appear within the role class at any place where feature declarations are allowed. It is denoted by

expected_method_designator -> provided_method_designator;

The effect is that any call to the role method will be forwarded to the associated base object using the provided base method.

Example code (Callout):
1
team class Company {
2
  public class Employee playedBy Person {
3
    abstract String getIdentification();
4
    // callout binding see below...
5
  }
6
}

(c) Kinds of method designators

A method designator may either be a method name

4
getIdentification -> getName;

or a complete method signature including parameter declarations and return type declaration, but excluding any modifiers and declared exceptions.

4
String getIdentification() -> String getName();
Effects:
  • Line 4 declares a callout binding for the role method getIdentification(), providing an implementation for the abstract method defined in line 3.
  • In combination with the role binding in line 2 this has the following effect:
  • Any call to Employee.getIdentification is forwarded to the method Person.getName.

Both sides of a callout binding must use the same kind of designators, i.e., designators with and without signature may not be mixed.
Each method designator must uniquely select one method. If a method designator contains a signature this signature must match exactly with the signature of an existing method, i.e., no implicit conversions are applied for this matching. If overloading is involved, signatures must be used to disambiguate.

(d) Inheritance of role method declarations

The role method being bound by a callout may be declared in the same class as the binding or it may be inherited from a super class or super interface.

(e) Callout override

If an inherited role method is concrete, callout binding regarding this method must use the token "=>" instead of "->" in order to declare that this binding overrides an existing implementation.
Using the "=>" operator for an abstract method is an error.
It is also an error (and not useful anyway) to callout-bind a method that is implemented in the same class as the binding.

(f) Inheritance of callout bindings

Callout bindings are inherited along explicit and implicit inheritance. Inherited callout bindings can be overridden using "=>".

(g) Duplicate bindings

It is an error if a role class has multiple callout bindings for the same role method.

(h) Declared exceptions

It is an error if a base method to be bound by callout declares in its throws clause any exceptions that are not declared by the corresponding role method.

(i) Shorthand definition

A callout binding whose method designators specify full method signatures does not require an existing role method. If no role method is found matching the expected method of such a callout binding, a new method is implicitly generated. The new method is static iff the bound base method is static, and it declares the same exceptions as the bound base method.

A shorthand callout may optionally declare a visibility modifier, otherwise the generated method inherits the visibility modifier of the bound base method. No further modifiers are set. If a callout overrides an inherited method or callout, it must not reduce the visibility of the inherited method/callout.

(j) Inferred callout

If a non-abstract role class inherits an abstract method the compiler tries to infer a callout binding for implementing the abstract method. Similarly, if a self-call in a role class cannot be resolved, the compiler tries to infer a callout to resolve the self-call.
Inference searches for a method in the bound base class such that

  1. both methods have the same name
  2. both methods have the same number of arguments
  3. each argument of the abstract role method is compatible to the corresponding argument of the base method directly, or using boxing/unboxing or lowering.

Callouts inferred from an interface have public visibility, callouts inferred from a self-call have private visibility.

Per default inferred callout bindings are disabled, i.e., a compiler must report these as an error. However, a compiler should allow to configure reporting to produce a warning only (which can be suppressed using a @SuppressWarnings("inferredcallout") annotation), or to completely ignore the diagnostic.

(k) Callout to generic method

When referring to a generic base method

1
<T> T bm(T a)

a callout binding may either propagate the method's genericity as in

2
<T> T rm(T a) -> T bm(T a);

or it may supply a valid substitution for the type parameter as in

2
String rm(String a) -> String bm(String a);

A callout binding either attaches an implementation to a previously declared method or adds (§3.1.(i) above) a forwarding method to a role class. Apart from this implementation, callout-bound methods do not differ from regular methods.

When we say, a callout binding defines forwarding this means that control is passed to the base object. In contrast, by a delegation semantics control would remain at the role object, such that self-calls would again be dispatched starting at the role. Callout bindings on their own do not support delegation. However, in conjunction with method overriding by means of callin bindings (see §4) the effect of delegation can easily be achieved.