Commit 9e2b772e authored by Matthias Simon's avatar Matthias Simon
Browse files

Add actual parameters

parent 8bbe1550
Loading
Loading
Loading
Loading
+436 −84
Original line number Diff line number Diff line
@@ -180,126 +180,478 @@ control {

### Actual parameters

An _actual parameter list_ supplies parameters to an invocation or
instantiation of a parameterized TTCN-3 language element. An _actual parameter
list_ may be written using _list notation_, _assignment notation_, or _mixed
notation_.

- empty parameter list may be omitted for parameterized object that are not functions, testcase, altstep, external functions
- notations
  - list notation
  - assignment notation (evaluated in order of actual arguments)
  - midex notation

- passing an parameter to a formal parameter is semantically equivalent to an assignment.
  - this implies that value expansion is (left-hand side reference semantics)
- 5.4.2.m aliasing (of structs and unions) in the same function is forbidden (can we actually enforce that?)


- actual parameters are mapped on the
- evaluated in the order they are passed
- evaluated in the scope of the caller
_- assignment list notation
- special rules altsteps, templates

- parameter kind:
    - in (default):
      - by value (copy, type compatibility)
      - optional default value (referencetypes == null)
      - recommended: no-side effects == constant evaluation
      - conflicting with: 5.4.1.1e
      - order
    - out:
      - by value (copy, type compatiblity)
      - copy back
    - inout:
      - by reference (type euqality, strong typing)
      - incremential changes visible
      - implcit deference
      - no reference to elements of string types

- default parameter

- non-l-values (values of templates, defaults, ... must be `in`

An _in-parameter_ is _passed by value_. 
A _out-parameter_ is also _passed by value_.
A _inout-parameter_ is _passed by reference_.

- expanding rules for referencing the elemnt on the left hand side. (6.2, 15.6)

It is allowed to pass elements of structured values or templates (record, set, record of, set of, union and anytype values
or templates) by reference. Modification of parameters passed this way affects the original structured value or template.
Before passing the actual parameter, the rules for referencing the element on the left hand side of assignments are
applied, expanding the structured value so that the referenced element becomes accessible (see clauses 6.2 and 15.6 for
more details).


```ttcn3 example = "unintended side-effects"
type component C {
    var integer cVar
**Syntactical Description**

```ebnf
ActualParList ::= "(" [ ActualPar {"," ActualPar} {"," ActualParAssignment}
                      | ActualParAssignment {"," ActualParAssignment} ] ")".
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. Its meaning for a
default formal parameter remains unresolved pending [default
parameters](#default-parameters). Its use for a variadic formal parameter is
specified in [variadic parameters](#variadic-parameters).

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.

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 altsteps shall be governed
by the `in` parameter semantics above because their formal parameters are
restricted to `in` 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.

**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 formal parameter that is neither a [default
   parameter](#default-parameters) nor a [variadic
   parameter](#variadic-parameters) shall be mapped exactly once.
4. The `-` omission marker shall not map to a formal parameter that is neither
   a default parameter nor a variadic 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 shall be governed
   by `in` parameter semantics because their formal parameters are restricted
   to `in` parameters.
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.

The omission rules for variadic parameters are specified in [variadic
parameters](#variadic-parameters). The omission rules for default parameters
remain unresolved pending rules in [default parameters](#default-parameters).

> NOTE: The source term “midex notation” is treated as a typographical error
> for _mixed notation_. The separate source fragment “assignment list
> notation” is incomplete and remains unresolved.

> NOTE: The source note `optional default value (referencetypes == null)` is
> ambiguous as to whether it concerns omitted actual parameters, initial
> values of reference types, or both. It remains unresolved; omission is
> reserved for [default parameters](#default-parameters).

> NOTE: The incomplete source fragment about non-left-hand-side values lists
> “defaults” without defining what kind of expression that term denotes.
> Whether it identifies an additional category remains unresolved.

> NOTE: The source prohibits passing an element of a string value to an
> `inout` formal parameter. The existing formal-parameter restriction more
> broadly prohibits string-type `inout` parameters, so no example can isolate
> the actual-parameter restriction. Their intended relationship remains
> unresolved.

> NOTE: Actual parameter expressions without side effects are recommended.
> The relationship of this recommendation to clause 5.4.1.1e remains to be
> resolved.

> NOTE: The behavior when an `out` formal parameter is not assigned, the point
> at which copy-back occurs, and the order of copy-back for multiple `out`
> parameters are not established by the source notes and remain unresolved.
> Whether `-` may discard an `out` result also remains unresolved and requires
> a rule in [default parameters](#default-parameters). The handling of a
> copied-back value that is outside the actual location's subtype or range also
> remains unresolved.

> NOTE: The source note “special rules altsteps, templates” does not identify
> any rule beyond the `in`-only restriction and the default and variadic rules
> cross-referenced above. Any additional rule remains unresolved and requires
> an authoritative source.

> NOTE: The [default parameters](#default-parameters) subsection does not yet
> specify omission or `-` behavior. Those cases remain unresolved here rather
> than being inferred.

> NOTE: The variadic subsection states both that an omitted or `-` actual
> parameter produces an empty `record of` value or template and, in its
> “default parameter” example, that the declared default is used. The
> precedence between these rules remains unresolved; the cross-reference does
> not settle this conflict.

> NOTE: The source identifies the left-hand-side element-reference and
> expansion rules as clauses 6.2 and 15.6, but corresponding targets are not
> available in the current Markdown sources. Their exact identification and
> cross-references remain unresolved.

> NOTE: How the aliasing prohibition of clause 5.4.2 m can be enforced,
> particularly when aliases arise through structured elements, remains
> unresolved.

> NOTE: Passing variables of components as `inout` parameters can cause
> unintended side effects and should be avoided.

> NOTE: The source's incomplete “pass reference by reference” component
> example does not contain an invocation or assignment. The intended behavior
> remains unresolved and requires a complete requirement before a normative
> example can be provided.

> NOTE: The source's empty “pass by value: changes not visible” example has
> been completed by the observable `changeCopy` example below.

**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
}
```

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.
```ttcn3 example="positional mapping"
function check(integer first, integer second, integer third) {
    // expect: first == 1, second == 2, third == 3
}

    log(cVar); // expected output: 99
control {
    check(1, 2, 3);
}
```

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

testcase tc() runs on C {
    f(cVar);
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="each invocation has its own copy"
```ttcn3 example="mixed mapping and evaluation order"
function next(inout integer n) return integer {
    n := n + 1;
    return n;
}

// each invocation of function `fib` has its own copy of parameter n.
function fib(in integer n) return integer {
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
}
```

```ttcn3 example="omitted empty actual parameter list"
template integer one() := 1;
template integer alsoOne := one; // equivalent to one()
```

```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 1;
    }
    return fib(n-2) + fib(n-1)
    return fibonacci(n - 2) + fibonacci(n - 1);
}

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

```ttcn3 example="pass by value: changes not visible"
function f(in integer i) {
```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="pass by reference"
function f(inout integer i) {
    i := i + 1;
```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 i := 0;
    f(i)
    log(i) // expected output: 1
    var integer n := 1;
    increment(n);
    log(n); // logs 2
}
```

```ttcn3 example="pass reference by reference"
// TODO: write test to change the passed inout variable to
type component PTC {}
```ttcn3 example="invalid compatible but non-identical inout type"
type integer Small (0..10);

testcase tc() {
    var PTC a := PTC.create("a");
    var PTC b := PTC.create("b");
function increment(inout integer p) {
    p := p + 1;
}

    var PTC c;
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
}

> NOTE: Passing variables of components as inout-parameter can cause unintended
> side-effects, and should be avoided.
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;
}

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

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

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

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);
}
```

### Default parameters