Statements are:
assignment
assignment attempt
procedure call
return
assertion
control structures
Control structures are described in section 11. This section only describes simple (non-compound) statements.
BNF:
statement ::= assignment
| assignment-attempt
| procedure-call
| return
| assertion
| ...
Values can be assigned to variables if the type of the value conforms to the type of the variable (see below for definition of conformance).
BNF:
assignment ::= ident-list ":=" expression-list
ident-list ::= identifier {"," identifier }
expression-list ::= expression {"," expression }
Examples:
a := 42
a, b, c := x, y, z - - multi-assignment (see below)
a, b, c := f()
The multi-assignment is defined as follows: Each of the expressions on the right hand side is evaluated to one or more values. (An identifier always evaluates to one value, a function evaluates to the list of its return values.) The order of evaluation is undefined. The values are then assigned to the identifiers on the left hand side. The number of identifiers must be equal to the number of values produced by the expressions on the right hand side. The first value is assigned to the first identifier, the second value to the second identifier, and so on. The evaluation of all expressions on the right hand side is always completed before any assignment is executed. This allows a statement like
a, b := b, a
to swap two values.
A type B conforms to a type A if
B is the same type as A
B is a (direct or indirect) subclass of A
Thus, the code segment
var
x: A
y: B - - B is subclass of A ...
y := create B
x := y
is legal, because B is a subclass of A, and so B conforms to A.
The variable x is said to have the static type A and the dynamic type B.
An assignment
a := b
is legal, if the static type of b conforms to the static type of a.
The assignment attempt allows an assignment from a variable a of some class to a variable b of a subclass. Such an assignment can be safely executed without risking type errors only if the dynamic type of a conforms to the static type of b.This can not be statically determined and causes a dynamic check to be executed.
BNF:
assignment-attempt ::= ident-list "?=" expression-list
ident-list ::= ident {"," ident }
expression-list ::= expression {"," expression }
Example:
var
x: A
y: B - - B is subclass of A ...
y ?= x
Statically, this assignment cannot be guaranteed to be successful (since the type of x does not conform to the type of y). x could reference an object of the dynamic type A. In that case the assignment cannot be executed, because y cannot hold references of type A. But x could also reference an object of the dynamic type B. In that case the assignment can be executed.
The assignment attempt results in a dynamic (runtime) check of the dynamic type of x. If the dynamic type of x conforms to the static type of y, the assignment will be executed, otherwise y will be assigned the value nil.
An assignment attempt
a ?= b
is statically legal if the static type of b conforms to the static type of a, or the static type of a conforms to the static type of b (in other words: if there is any chance that the assignment could be successful).
A procedure call is a call to a routine that does not return parameters.
BNF:
procedure-call ::= call-chain
call-chain ::= [ super "!" ] unqualified-call { "." unqualified-call }
unqualified-call ::= identifier [ "(" expression-list ")" ]
Examples:
proc
proc (a,b)
obj.proc (a, 23+17)
alist.get (22).put ("hello")
A procedure call can be a call of either an internal or external procedure. An internal procedure is a procedure that is defined in the same class containing the procedure call. An external procedure is a procedure defined in another class. External procedure calls are preceded by an object identifier, separated from the procedure name by a dot (.). If a procedure has parameters, the call has a list of the actual parameters in parenthesis. If no parameter list exists, no parenthesis are written.
The return instruction causes a return from a routine.
BNF:
return ::= return
Example:
show is
== displays this element on standard output do
if name = "" then
return
...
end show
return does not take any parameters. If the routine is a function, all return values must be assigned before the return is executed.
Routine exits from anywhere in a routine (even in the middle of a loop!) are seen by some as "unstructured programming". For a good summary of the reasons that show the advantages (in terms of programming and teaching) of this construct, see Roberts, E., Loop Exits & Structured Programming: Reopening the Debate, SIGCSE Bulletin, 27, 1, March 1995, pp. 268-272
Assertions are used as a tool for correctness assurance and debugging.
BNF:
assertion ::= assert "(" condition ")"
condition ::= boolean-expression
Example:
assert (name <> nil)
If the boolean expression in the assertion is not true, program execution is interrupted and the user is notified about failing of the assertion. If the expression is true, the statement has no effect.