Method Access & Calls

Methods of a Class, Record or Interface can be accessed simply by specifying their name.

For methods of the current type (i.e. the class or record that the current code is also a part of), simply the name of the method on its own suffices to access it. To access methods on a different type (or a different instance of the same type), a Member Access Expression is used, appending an . or : to the expression that represents the instance, followed by the method name.

By default, accessing a method means to call it, unless the expression is preceeded by an @ Address-Of operator, or the surrounding context suggests that the address of the method is expected. More on that below.

Parameter-less methods can be called with just their name, or an optional empty set of parenthesis (()). For methods that require parameters, these must be provided in parenthesis after the method name:

type
  Foo = public class
  private
    method Print; 
    method Update(aValue: String);
    
  public
  
    method Test(aBar: Bar);
    begin
      Print;
      Update(aBar.Name);
      aBar.NortifyOfUpdate(self);
    end;

  end; 

In the above example, Print and Update can be called directly, as methods on the current instance of the class. A Member Access Expression is used to call the NortifyOfUpdate method on aBar – a different object.

Using self to Avoid Ambiguity

The self expression can be used to explicitly access a method on the current instance, in cases where the name of the field is hidden by a different identifier in scope:

method Test(aBar: Bar);
begin
  var Print := new StarryNight(5, 10);
  ...
  self.Print;
end;

In the above example, the local Print variable (which really should have been named lPrint) hides the Print method. Via the self keyword it can still be called. In this case simply adding parenthesis, Print(), would also have resolved the ambiguity.

Generic Parameters

Methods might be defines with generic parameters. In most cases, these can be inferred from parameters of the method call, but sometimes it might be necessary to explicitly specify them, using angle brackets between the method name and the (optional) parameter list:

var x := lStringList.Select<Integer>(s -> length(s));

The above example would compile without the explicit <Integer> because the type can be inferred from the code in the Lambda Expression, but it is good to have the option to be explicit.

Multi-Part Method Names

Methods can have Multi-part Method Names that give a more expressive description for individual parameters. The individual parts of the method name will be used for the call in the same way as they are in the declaration, with each part being followed by a set of parenthesis containing a subset of parameters:

lObject.RunCommand('ebuild') Arguments('MyProject.sln', '--configuration:Debug');

Trailing Closures

If the last parameter of a Method (or Constructor) is a Block type used as a callback, rather than passing a method name or Anonymous Method, the block can follow the method call as a "trailing closure". This allows for a more natural integration of the callback into the flow of code and essentially makes the method call feel more like a native language construct being followed by an begin/end block:

The following snippet shows a call to dispatch_async with a trailing closure:

dispatch_async(dispatch_get_main_queue) begin
    // do work on the main thread
end;

If the closure receives any parameters, their names will be inferred from the declaration of the method or the Block type used in the declaration, and become available as if they were local identifiers:

remoteAdapter.beginGetDataTablewWithSQL('SELECT * FROM FOO') begin
    writeLn(table)
end;

To avoid ambiguity, trailing closures are not supported inside require/ensure clauses of Class Contracts.

Getting the Address of a Method

Sometimes, instead of calling a method, one needs to obtain its address – typically to assign to an Event or pass it as a Block. There are two ways to achieve this.

Preceding the method access expression with the @ Address-Of operator will always return its address:

var m := @lMyObject.Foo; // get the address
...
m(); // call it, later

Alternatively the compiler will also infer that the address of the method is requested, based on the context the method access expression is used in – for example when assigning to a Block type variable/parameter or to an event via +=/-=:

Button.Click += OnClick;
var callback: block := OnSuccess;

Note that parenthesis after the method name are not permitted when obtaining a method's address. In fact, specifying either @ or an empty set of () can resolve (rare) ambiguities where both the methods address or its result would be valid (for example, if the method's return value is a block of the same type as the method itself).

See Also