ziggy@hx.lcs.mit.edu (Michael R. Blair) (04/11/91)
In the ongoing to-specify-or-not-to-specify-order-of-arg-eval debate,
Jinx has offered the following and asks if anyone objects:
jinx> All the even numbered arguments are evaluated first from right to
jinx> left, and then the odd numbered arguments are evaluated from left
jinx> to right.
I object strenuously to this. The reason: it would still be possible for me
to inadvertently supply to a procedure call two arguments which interfere
(one affecting the value of the other) in an unanticipated way which I did
not intend yet not detect it when testing my code.
I think the only well-reasoned way to avoid this is by one the following:
[1] Tell the user that the order of evaluation of arguments is as
Jinx has suggested but with the additional behavior that:
a. For each argument, we consider the position of the argument
within the argument list as viewed left-to-right, the leftmost
argument being at position 1 (by definition of ``position''...
this is *not* ``index'': ``index'' starts at 0).
b. Consider the number of arguments in the application. Call it A.
c. Arguments are evaluated as follows:
All the even numbered arguments are arg-evaluated first from right
to left, and then the odd numbered arguments are arg-evaluated from
left to right.
d. Arg-evaluation is like normal evaluation except that it considers the
position of the argument being evaluated as well as the number of argu-
ments A, as follows:
i) When an even numbered argument at position P is arg-evaluated, it is
evaluated A+P-1 times and the value of the A-P+1th evaluation is
returned.
ii) When an odd numbered argument at position P is arg-evaluated, it is
evaluated A+P+1 times and the value of the (1 + (A mod P))th eval-
uation is returned.
This has the advantage of evaluating arguments multiple times (of course,
side-effect free arguments need be evaluated only once... whether or not
a side-effect has occurred can be run-time checked to decide if further
evaluation is needed) in a deterministic fashion, but one that is
sufficiently non-obvious that programmers are quite unlikely to not detect
an inadvertent mutational argument. It is also sufficiently computationally
straightforward that proofs of program correctness would not increase in
obtuseness to any appreciable degree.
[2] An alternative is to specify left-to-right evaluation but where all writes
to the store incurred by this evaluation will be postponed until all
arguments have been evaluated and where only the last write to a location
will take effect.
[3] Specify that no argument in a given argument list may incur a write effect
on any location which another arguments reads or writes. Make implementa-
tions signal a runtime error when this restriction is not observed. The
inefficiency this may impose on an implementation is far outweighed by the
convenience it affords the naive user in being able to perform arbitrary
mutation within an argument list without regard to the semantic consequence
since the implementation will detect any possible problems.
[4] Require that arguments be only variable references, not calls to other
procedures. This simple syntactic restriction obviates the entire issue.
[5] Introduce a new special form (as Mark Day suggested):
(WITH-ARGUMENT-EVALUATION-ORDER (1 3 2 5 4)
(foo (zap x) (baz (bar x)) (zorch x) (+ x 1)))
which explicitly declares the argument evaluation order for the application
in question. In the above, FOO is evaluated first followed, in turn, by
(baz (bar x)) then (zap x) then (+ x 1) then (zorch x). Note that any one
of these arguments could itself have used WITH-ARGUMENT-EVALUATION-ORDER.
[6] Prescribe a standard text string hash function and specify that a stable
sort be performed on the hashed textual appearance of each argument. This
sort specifies the order in which the arguments are to be evaluated.
I hope you find some of these suggestions intriquing so that we can continue
this very fascinating discussion of the virtues of specifying an evaluation
order so that I can some day reap all the benefits of a prescribed evaluation
order. After all, using LET* just to get the side effects right before a
procedure call is very distracting... it makes me stop and think about the
side-effects that will be incurred when what I really want to think about is
the single computation event that the application as a whole represents.
-zorchy
--
zorchy@flame.athena.mit.edu a.k.a. Reginald Zorakowski
``To err is human. I am human. Draw your own conclusion, bub.''