[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Side effecting constants inside functions



    Date: Tue, 20 Aug 85 02:52:22 EDT
    From: Tim McNerney <TIM@MIT-MC.ARPA>

    In CLtL, I can't find any mention of the issue of side effecting
    internal constants.  In Maclisp, NIL, Zetalisp, and presumably most
    Common Lisp implementations, the function:

      (defun withdraw (amount)
        (let ((balance '(1000)))
          (decf (first balance) amount)))

    acts much like a lexical closure with a local state variable.
    Thus, (withdraw 100) => 900, then (withdraw 100) => 800, etc.  This 
    behaviour has always bothered me.  Is this rather questionable style 
    condoned by Common Lisp?

This extremely questionable style is considered "an error" in both Maclisp
and NIL, which take the view that such constants are permissible to be made
read-only, and potentially made EQ to other constants which are EQUAL.

    Efficiency aside, it would be cleaner for the semantics of a function
    which side effects its internal constants to be as though a fresh copy
    were made each time the function was evaluated, effectively making
    '(1000) == (list 1000) and #(1 2 3) == (vector 1 2 3), etc.  This way,
    the above function would always return 900.

Please take 2000 mg of Thorazine, and 10 mg cogentin to counteract the
smooth muscle contractions which might ensue.  This might help to reduce
the level of distortion in your perception.

    If such a function is to behave as it does in Maclisp, there is a subtle
    issue having to do with the interaction between the interpreter and the
    compiler:  Should COMPILE reset the local state of such a function?
    (In NIL and Zetalisp it doesn't, but one can imagine that a "digested"
    copy of the original lambda expression might be cached by the interpreter,
    and that the compiler uses the original unscathed version).

In a standard Maclisp scenario of loading compiled code, purifying and dumping
the environment, this does not work.  In NIL when the code is compiled this
does not work, as such constants in compiled code in NIL are cuurently ALWAYS
read-only.  If i interpret "reset the local state of such a function"
correctly, NIL always does so, since currently the in-core compilatioin is
only a kludge of to-file compilation so no datastructure gets preserved.
Otherwise, NIL never bashes anything, and such things as cached macro
expansions performed by the interpreter have absolutely no effect on the
expansions performed by the compiler.

    	Timothy Leary

Glenn S. Burnout

p.s.  I have a manic-depressive friend who, while i haven't seen him
in a number of years, i can probably track down if given a few hours.
He would no doubt have a good supply of thorazine, cogentin, and
lithium on hand.