Commit 97e911b6 authored by Matthias Simon's avatar Matthias Simon
Browse files

Restored old actual parameters chapter

parent a69899c5
Loading
Loading
Loading
Loading
+41 −393
Original line number Diff line number Diff line
@@ -194,414 +194,57 @@ ActualPar ::= Expr | Expr "..." | "-".
ActualParAssignment ::= name ":=" Expr.
```

In _list notation_, each actual parameter is an `ActualPar`. In _assignment
notation_, each actual parameter is an `ActualParAssignment`. In _mixed
notation_, one or more `ActualPar` entries are followed by one or more
`ActualParAssignment` entries.

The `...` suffix is used only when passing an actual parameter to a variadic
formal parameter as described in [variadic parameters](#variadic-parameters).

The `-` symbol is the omission marker in list notation. For a default formal
parameter it selects the declared default as specified in [default
parameters](#default-parameters). For an `out` formal parameter it discards
copy-back. Its use for a variadic formal parameter is specified in [variadic
parameters](#variadic-parameters).
- notations
  - list notation
  - assignment notation
  - mixed notation

The parentheses of an empty actual parameter list may be omitted for a
parameterized language element other than a function, external function,
testcase, or altstep.

**Semantic description**

In list notation, actual parameters shall map by position: the first actual
parameter maps to the first formal parameter, the second actual parameter maps
to the second formal parameter, and so on.

In assignment notation, each actual parameter shall map to the formal parameter
whose name occurs before `:=`. That name shall identify a formal parameter of
the invoked language element. The order of the formal parameter declarations
does not determine the order of the actual parameter assignments.

In mixed notation, the leading list entries shall map by position. Each
following assignment entry shall map by name. An assignment entry shall not map
to a formal parameter already mapped by a preceding list entry.

Actual parameters shall be processed in their textual order in the actual
parameter list, irrespective of the notation used. For each actual parameter,
its expression shall be evaluated where applicable and the initial assignment
or binding required by the mapped formal parameter's kind shall be completed
before processing of the next actual parameter begins. The assignment and
binding semantics for `in`, `out`, and `inout` parameters are specified below;
subsequent copy-back semantics are not part of this initial processing order.
This order is specified by the [actual-parameter source
text](../std/args.md#actual-parameters).

An actual parameter expression shall be evaluated in the scope of the caller.
Names in that expression therefore denote declarations visible at the point of
invocation, not declarations in the invoked language element.

As specified in [formal parameters](#formal-parameters), a formal parameter
without an explicit direction is an `in` formal parameter.

For an `in` formal parameter, the value of the actual parameter shall be
assigned to distinct storage for the formal parameter before invocation. The
type of the actual parameter shall be compatible with the type of the formal
parameter. Subsequent assignment to the formal parameter shall not modify the
actual parameter.

For an `out` formal parameter, distinct storage shall be provided for the
formal parameter. No value shall be copied from the actual parameter into that
storage. The final value of the formal parameter shall be copied back to the
actual parameter. The formal parameter type shall be compatible with the type
of the writable actual location; this compatibility shall be checked before
invocation.

For an `inout` formal parameter, the actual parameter shall be bound by
reference; no separate value shall be copied in or copied back. The type of the
actual parameter shall be identical to the type of the formal parameter.
Reading or assigning the formal parameter shall implicitly dereference that
binding, and each assignment shall therefore be immediately observable through
the actual parameter.

Passing an actual parameter to a formal parameter shall have the assignment
semantics of the mapped parameter kind. When an element of a structured value
or structured template is passed to an `out` or `inout` formal parameter, the
applicable left-hand-side element-reference and expansion rules shall be
applied before the parameter is passed, so that the referenced element is
accessible.

An element of a record, set, `record of`, `set of`, union, or `anytype` value or
template may be passed by reference when it otherwise satisfies the
requirements for an `inout` actual parameter. Assignment through the formal
parameter shall then modify that element of the original structured value or
template.

The actual parameters of parameterized templates and of altsteps activated as
defaults shall be governed by the `in` parameter semantics above because their
formal parameters are restricted to `in` parameters. Directly invoked
altsteps may also have `out` and `inout` parameters. Their default and
variadic actual parameters shall additionally follow [default
parameters](#default-parameters) and [variadic
parameters](#variadic-parameters), respectively.

Clause 5.4.2 m prohibits aliasing structured values and unions within the same
function. In permitted cases, such as the scalar component variable in the
example below, two accessible names may denote the same location during an
invocation; assignment through an `inout` formal parameter is then observable
through either name.
- To invoke a parameterized TTCN-3 language elements, its actual parameters are evaluated and assigned to the formal parameters.
- for functions: then control is transfered
- for templates: see section 15 (parameterized templates)
- for altsteps, testcases, ...: ?

- actual parameters are evaluated in order of their appearance
- evaluated in the scope of the caller
- assignment notation: each parameter shall be specified only once.
- parameter kinds
    - in:
      - _pass by value_ (copy, type compatibility)
      - optional default value (reference-types == null)
      - recommended: no-side effects == constant evaluation
      - expand values according to right-hand-side-semantics ([assignment])
    - out:
      - _pass by value_ (copy, type compatibility)
      - copy back when changed
      - expand values according to left-hand-side-semantics ([assignment])
    - inout:
      - _pass by reference_ (type equality required, strong typing)
      - expand values according to left-hand-side-semantics ([assignment])

**Restrictions**

1. An `ActualPar` shall not follow an `ActualParAssignment` in the same actual
   parameter list.
2. Except for the list-notation rules for a [variadic
   parameter](#variadic-parameters), no formal parameter shall be mapped more
   than once in the same actual parameter list.
3. Each `inout` formal parameter and each `in` formal parameter that is neither
   a [default parameter](#default-parameters) nor a [variadic
   parameter](#variadic-parameters) shall be mapped exactly once. An `out`
   formal parameter may be omitted.
4. The `-` omission marker shall map only to an `out`, default, or variadic
   formal parameter.
5. An actual parameter mapped to an `out` or `inout` formal parameter shall
   denote a writable location. A literal, expression result, constant,
   template value, or other non-left-hand-side value shall be mapped only to an
   `in` formal parameter.
6. Actual parameters of parameterized templates and altsteps activated as
   defaults shall be governed by `in` parameter semantics because their formal
   parameters are restricted to `in` parameters. Directly invoked altsteps may
   use the applicable `in`, `out`, and `inout` semantics.
7. In accordance with clause 5.4.2 m, an actual parameter list shall not create
   prohibited aliases of structured values or unions within the same function.

An omitted `out` formal parameter is treated as if `-` had been supplied, and
no value is copied back for it. Values assigned to mapped `out` formal
parameters shall be copied back in formal-parameter order. If no value was
assigned to a mapped `out` formal parameter, its actual location shall remain
unchanged, as specified by the [actual-parameter source
text](../std/args.md#actual-parameters).

The omission rules for default and variadic parameters are specified in
[default parameters](#default-parameters) and [variadic
parameters](#variadic-parameters), respectively.

> NOTE: Actual parameter expressions without side effects are recommended.
> NOTE: Passing variables of components as `inout` parameters can cause
> unintended side effects and should be avoided.

**Examples**

```ttcn3 example="actual parameter notation"
function f(integer p, integer q, integer r) {}

control {
    f(1, 2, 3);                 // list notation
    f(p := 1, q := 2, r := 3); // assignment notation
    f(1, q := 2, r := 3);      // mixed notation
    f(p := 1, 2, 3);           // error: list entry follows assignment
}
```

```ttcn3 example="positional mapping"
function check(integer first, integer second, integer third) {
    // expect: first == 1, second == 2, third == 3
}

control {
    check(1, 2, 3);
}
```

```ttcn3 example="named mapping and evaluation order"
function next(inout integer n) return integer {
    n := n + 1;
    return n;
}

function check(integer first, integer second, integer third) {
    log(first, second, third); // logs 2, 1, 3
}

control {
    var integer n := 0;
    check(second := next(n), first := next(n), third := next(n));
    // The expressions are evaluated in textual order, not formal-parameter order.
}
```

```ttcn3 example="mixed mapping and evaluation order"
function next(inout integer n) return integer {
    n := n + 1;
    return n;
}

function check(integer first, integer second, integer third) {
    log(first, second, third); // logs 1, 3, 2
}

control {
    var integer n := 0;
    check(next(n), third := next(n), second := next(n));
    // The positional entry maps first; named entries map and run as written.
}
```

```ttcn3 example="invalid duplicate mapping"
function f(integer p, integer q) {}

control {
    f(1, p := 2);          // error: p is mapped twice
    f(p := 1, p := 2);     // error: p is mapped twice
}
```

```ttcn3 example="invalid named and missing mappings"
function f(integer p, integer q) {}

control {
    f(p := 1, unknown := 2); // error: unknown is not a formal parameter
    f(p := 1);               // error: required formal parameter q is not mapped
}
```

```ttcn3 example="invalid omission of required parameter"
function f(integer required) {}

control {
    f(-); // error: required is neither default nor variadic
}
```

```ttcn3 example="evaluation in caller scope"
const integer offset := 1;

function add(integer value) return integer {
    const integer offset := 100;
    return value;
}

control {
    var integer base := 2;
    var integer result := add(base + offset);
    log(result); // logs 3, because offset is resolved in the caller's scope
}
```
- Passing references of fields or elements and references to the container in the same actual parameter list is forbidden; to prevent aliasing related issues.
- values that that cannot be used on the left-hand-side of an assignment, must also be `in
- empty parameter list may be omitted for parameterized object that are not functions, testcase, altstep, external functions

```ttcn3 example="omitted empty actual parameter list"
template integer one() := 1;
template integer alsoOne := one; // equivalent to one()
```
> TODO: Check 5.4.2.m aliasing (of structs and unions) in the same function is forbidden (can we actually enforce that?)

```ttcn3 example="in parameter uses a compatible copy"
type integer Small (0..10);

function changeCopy(in integer p) {
    p := 9;
}

control {
    var Small n := 2;
    changeCopy(n); // Small is compatible with integer
    log(n);        // logs 2: p has distinct storage
}
```

```ttcn3 example="each invocation has its own parameter copy"
function fibonacci(in integer n) return integer {
    if (n < 2) {
        return 1;
    }
    return fibonacci(n - 2) + fibonacci(n - 1);
}

control {
    var integer result := fibonacci(2);
    log(result); // logs 2
}
```

```ttcn3 example="out parameter copies its final value back"
type integer Small (0..10);

function produce(out integer p) {
    p := 7;
}

control {
    var Small result := 0;
    produce(result);
    log(result); // logs 7: compatible types need not be identical
}
```

```ttcn3 example="inout parameter is implicitly dereferenced"
function increment(inout integer p) {
    p := p + 1;
    log(p); // logs 2 through the binding to n
}

control {
    var integer n := 1;
    increment(n);
    log(n); // logs 2
}
```

```ttcn3 example="invalid compatible but non-identical inout type"
type integer Small (0..10);

function increment(inout integer p) {
    p := p + 1;
}

control {
    var Small n := 1;
    increment(n); // error: compatible types are not sufficient for inout
}
```

```ttcn3 example="invalid non-lvalue actual parameters"
const integer fixed := 0;
template integer pattern := 1;

function setOut(out integer p) {
    p := 1;
}

function setInout(inout integer p) {
    p := 1;
}

control {
    setOut(0);          // error: a literal is not a writable location
    setInout(1 + 2);    // error: an expression result is not a writable location
    setOut(fixed);      // error: a constant is not writable
    setOut(pattern);    // error: a template value is not a writable value
}
```

```ttcn3 example="invalid incompatible in and out types"
function consume(in integer p) {
}

function produce(out integer p) {
    p := 1;
}

control {
    var charstring text := "x";
    consume(text); // error: charstring is not compatible with integer
    produce(text); // error: integer cannot be copied back to charstring
}
```

```ttcn3 example="structured element passed by reference"
type record Pair {
    integer left,
    integer right
}

function increment(inout integer p) {
    p := p + 1;
}

control {
    var Pair pair := { left := 1, right := 2 };
    increment(pair.left);
    log(pair); // logs { left := 2, right := 2 }
}
```

```ttcn3 example="structured element receives out copy-back"
type record Pair {
    integer left,
    integer right
}

function produce(out integer p) {
    p := 7;
}
**Examples**

```ttcn3 example="each parameter only once"
external function f(in integer p1, in integer p2 := 99);
control {
    var Pair pair := { left := 1, right := 2 };
    produce(pair.right);
    log(pair); // logs { left := 1, right := 7 }
    f(1, p1:= 2); // error
}
```

```ttcn3 example="structured template element passed by reference"
type record Pair {
    integer left,
    integer right
}

function replace(inout template integer p) {
    p := 3;
}

```ttcn3 example="non left-hand-side value"
external function f(inout integer p1);
control {
    var template Pair pattern := { left := 1, right := ? };
    replace(pattern.left);
    log(pattern); // logs { left := 3, right := ? }
}
```

```ttcn3 example="unintended side effects"
type component C {
    var integer cVar;
}

function f(inout integer p) runs on C {
    cVar := 10;
    p := 99; // changing p also changes cVar, because both are
             // references to the same piece of data.

    log(cVar); // expected output: 99
}

testcase tc() runs on C {
    f(cVar);
    f(bit2int('1100101')); // error: reference to temporary value
}
```

@@ -667,6 +310,11 @@ variadic-parameter rules.

**Examples**

```
f(1, -) // the same
f(1)
```

```ttcn3 example="default omission and dash marker"
function report(integer value, integer base := 10, integer width := 2) {
    log(value, base, width);