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.''