Skip to content

Calls

Calls are used to trigger the execution of a specific action, which can, for example, be the creation of an instance of a class or executing the code in a segment. Let's look at an example:

First, we show the code of the segment that we want to call.

segment createDecisionTree(maxDepth: Int = 10) {
    // ... do something ...
}

This segment has a single parameter maxDepth, which must have type Int, and has the default value 10. Since it has a default value, we are not required to specify a value when we call this segment. The most basic legal call of the segment is, thus, this:

createDecisionTree()

This calls the segment createDecisionTree, using the default maxDepth of 10.

The syntax consists of these elements:

  • The callee of the call, which is the expression to call (here a reference to the segment createDecisionTree)
  • The list of arguments, which is delimited by parentheses. In this case the list is empty, so no arguments are passed.

If we want to override the default value of an optional parameter or if the callee has required parameters, we need to pass arguments. We can either use positional arguments or named arguments.

In the case of positional arguments, they are mapped to parameters by position, i.e. the first argument is assigned to the first parameter, the second argument is assigned to the second parameter and so forth. We do this in the following example to set maxDepth to 5:

createDecisionTree(5)

The syntax for positional argument is simply the expression we want to pass as value.

Named arguments, however, are mapped to parameters by name. On the one hand, this can improve readability of the code, since the meaning of a value becomes obvious. On the other hand, it allows to override only specific optional parameters and keep the rest unchanged. Here is how to set maxDepth to 5 using a named argument:

createDecisionTree(maxDepth = 5)

These are the syntactic elements:

  • The name of the parameter for which we want to specify a value.
  • An equals sign.
  • The value to assign to the parameter.

Passing Multiple Arguments

We now add another parameter to the createDecisionTree segment:

segment createDecisionTree(isBinary: Boolean, maxDepth: Int = 10) {
    // ... do something ...
}

This allows us to show how multiple arguments can be passed:

createDecisionTree(isBinary = true, maxDepth = 5)

We have already seen the syntax for a single argument. If we want to pass multiple arguments, we just separate them by commas. A trailing comma is allowed.

Restrictions For Arguments

There are some restriction regarding the choice of positional vs. named arguments and passing arguments in general:

  • For all parameters of the callee there must be at most one argument.
  • For all required parameters there must be exactly one argument.
  • After a named argument all arguments must be named.

Depending on the callee, a call can do different things. The following table lists all legal callees and what happens if they are called:

Callee Meaning
Class Create a new instance of the class. The class must have a constructor to be callable. The call evaluates to this new instance.
Enum Variant Creates a new instance of the enum variant. Enum variants are always callable. The call evaluates to this new instance.
Global Function Invokes the function and runs the associated Python code. The call evaluates to the result record of the function.
Method Invokes the method and runs the associated Python code. The call evaluates to the result record of the method.
Segment Invokes the segment and runs the Safe-DS code in its body. The call evaluates to the result record of the segment.
Block Lambda Invokes the lambda and runs the Safe-DS code in its body. The call evaluates to the result record of the lambda.
Expression Lambda Invokes the lambda and runs the Safe-DS code in its body. The call evaluates to the result record of the lambda.
Declaration with Callable Type Call whatever the value of the declaration is.

Result Record

The term result record warrants further explanation: A result record maps results of a

to their computed values.

If the result record only has a single entry, its value can be accessed directly. Otherwise, the result record must be deconstructed either by an assignment (can access multiple results) or by a member access (can access a single result).

Null-Safe Calls

If an expression can be null, it cannot be used as the callee of a normal call. Instead, a null-safe call must be used. A null-safe call evaluates to null if its callee is null. Otherwise, it works just like a normal call. This is particularly useful for chaining.

The syntax is identical to a normal call except that we replace the () with ?():

nullableCallee?()