Node:Statement sequences, Next:False and multiple values, Up:Control structure
Q is an expression language, which means it does not distinuish statements from expressions. However, it is not a purely functional language: an expression may have a side effect, such as writing a value to a file. So it is useful to combine two or more expressions, evaluating them in order. Such a statement sequence is written as a list of expressions separated by semi-colons or new-lines.
The value that results from evaluating a statement sequence is essentially the concatenation of the values of the sub-expressions. This makes sense because the result of a command that runs a program is the text printed (on standard output) by the command, so the result of running two commands in sequence should be the concatendation of their outputs.
Declarations, assignments, and constraints are kinds of expressions that we evaluate for their side-effects. If they "succeed," we don't want anything printed. We do this by having such expressions evaluate to the null sequence. Concatenating a value with the null sequence yields the orginal value. It is useful to be able to evaluate a series of declarations, assignments, and constraints, and then evaluate a final expression, returning that final result. We can do this if when "concatenating" the sub-expressions of a statement sequence, if all of the results but one are null, return the non-null result. This is not what is normally meant by "concatenation," but it is a convenient extension.
So, in detail, the effect of evaluating expr1; expr2
is the following:
sprintf "%s%s" value1 value2
.
Note: this definition satisfies the following properties:
(a; b); c
= a; (b; c)
[];a
= a;[]
= a
("string1"; "string2")
= "string1string2"
sprintf "%s" (a;b)
= (sprintf "%s" a; sprintf "%s" b)
Note that a statement list delimits the scope of a declaration within it: See Block structure. Also, if any declaration defined within the list is exported, the block evaluates to a record.