Output locals can be assigned to anywhere in the procedure. When the procedure finishes, the values of the output locals are left on the stack. In the example above the values are then taken off the stack after the procedure STATS has finished, and assigned to A and to S.
It may be useful to remember the following "symmetry" between the "input variable" numlist, and the "output" variables, average and sum, in the definition of stats:
define stats(numlist) ->(average, sum); etc...(a) The input variables are used without any assignment arrow, yet values are ASSIGNED TO THEM from the stack when the procedure starts up.
(b) The output variables appear to be preceded by an assignment arrow, yet their values are copied to the stack when the procedure finishes: the reverse of an assignment.
This is the reverse of what happens when a procedure is invoked with actual arguments:
stats(list) -> (a, s);Here, before the procedure runs: (c) a value is taken FROM the variable "list" and copied to the stack,
(d) and when the procedure has finished two items at the top of the stack are moved into the variables a and s.
So (a) is the reverse of (c) and (b) is the reverse of (d). Nevertheless the same syntactic form is used in both the header of a procedure definition and in a later invocation of the procedure. The procedure header gives a sort of "template" for using the procedure.
As a reminder of points made in the previous chapter, the procedure form:
define foo(i1, i2) -> (r1, r2); <instructions> enddefine;can be thought of as roughly meaning
To do sumsq; make i1, i2, r1, r2 lexical local variables for the procedure sumsq. -> i2; -> i1; <do the procedure instructions> put value of r1 on stack. put value of r2 on stackNote that the order in which values for i1 and i2 are taken off the stack is the reverse of the order in which they are put on the stack when the procedure is invoked. This is because it is a stack!