ksr@vax135.UUCP (Ken Roberts) (07/22/86)
There is an interesting subtlety about local variables and parameter passing in the MLisp of Unipress (Gosling) Emacs. Suppose I define the functions 'insert-times' and 'my-test': (defun (insert-times this-string n ; Inserts 'n' (argument 2) copies ; of the string given by 'this-string' (argument 1). (setq this-string (arg 1)) (setq n (arg 2)) (while (> n 0) (setq n (- n 1)) (insert-string this-string) ) ) ) (defun (my-test this-string (insert-times "Hello--" 2) (setq this-string "Hello--") (insert-times this-string 2) ) ) If I now invoke the function 'my-test', what will be inserted is not "Hello--Hello--Hello--Hello--", but rather "Hello--Hello00". This is because the expression for argument 1 is not evaluated at the time of the invocation of 'insert-times'; but rather when (arg 1) is reached. By that time, the name 'this-string' has been rebound, and initialized to 0 (by the new local declaration in the function 'insert-times'). Conclusion: Due to the way the 'arg' function is defined, local variables are not entirely insulated from other variables (local or global) that have the same name. This is a problem, since the major selling point of local variables is supposed to be that you are free to choose names for them without bothering to check if those names are already being used somewhere else. Ken Roberts
mg@unirot.UUCP (Mike Gallaher) (07/29/86)
> Conclusion: Due to the way the 'arg' function is defined, local > variables are not entirely insulated from other variables > (local or global) that have the same name. > > This is a problem, since the major selling point of local variables > is supposed to be that you are free to choose names for them > without bothering to check if those names are already being used > somewhere else. This is indeed one of the most confusing subtleties of MLisp. (It wasn't even documented anywhere before V2.10!) Once you understand what is going on, it is not hard to avoid problems. The MLisp coding guidelines (doc/mlisp-std) recommend that local variable names be prefixed by some string unique to the function it is defined in. For instance, a function called describe-moused-word might have a variable $dmw-count. (The '$' is a naming convention indicating that it is a local variable.) Also, be careful about evaluating args that may depend on which buffer is current, or where the region is, etc. For instance, suppose you have (defun (foo (temp-use-buffer "*scratch*" (setq @foo (arg 1)) ) )) (mark-whole-buffer) (foo (region-to-string)) foo will evaluate the argument, (region-to-string), within the buffer *scratch*, not in the buffer from which foo was called. Though you can usually write the code so as not to depend on such things, the most general way around this problem is to have functions evaluate their arguments and store the results in local variables before doing anything else: (defun (foo $s (setq $s (arg 1)) (temp-use-buffer "*scratch*" (setq @foo $s) ) )) Once you come to properly love MLisp, you will realize that you wouldn't want it to be any other way. :-) Mike Gallaher Unipress Software