charest@ai-cyclops.jpl.nasa.gov (02/28/91)
I want to define a function that performs a certain computation on its first invocation and performs a different computation on all subsequent invocations. Consider the trivial (but representative) example below: (defun mutate (list) (let ((len (length list))) (prog1 list (compile 'mutate `(lambda () ,len))))) 1> (mutate '(a b c)) => (a b c) 2> (mutate '(a b c)) => Error: too many arguments to function mutate. 3> (mutate) => 3 My question is, Will this function behave as expected (i.e., as described above) in any Common LISP? More specifically, is it safe to modify the contents of a symbols' function cell even as the contents are being executed? I can find nothing in CLtL2 that addresses this. I welcome all opinions, learned or otherwise. -Len Charest charest@ai-cyclops.jpl.nasa.gov
barmar@think.com (Barry Margolin) (02/28/91)
In article <11609@jpl-devvax.JPL.NASA.GOV> charest@ai-cyclops.jpl.nasa.gov writes: >More specifically, is it safe to modify the contents >of a symbols' function cell even as the contents are being executed? I believe it is, but there are some rules. CLtL doesn't address these problems, but the X3J13 Compiler Committee did some work to tighten up this area. Here are relevant excerpts from the proposal that was approved: (b) The compiler may assume that, within a named function, a recursive call to a function of the same name refers to the same function, unless that function has been declared NOTINLINE. (c) COMPILE-FILE may assume that, in the absence of NOTINLINE declarations, a call within the file being compiled to a named function which is defined in that file refers to that function. (This permits "block compilation" of files.) The behavior of the program is unspecified if functions are redefined individually at runtime. Point (b) is not directly applicable to your example, but it would be to a modified version that ends with a recursive call to the function. However, point (c) is applicable if there are calls to the function in other parts of the file. In both cases, preceding the definition with a (proclaim '(notinline mutate)) should make things safe. -- Barry Margolin, Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar
Jenny.Rowland@levels.sait.edu.au (03/14/91)
In article <11609@jpl-devvax.JPL.NASA.GOV>, charest@ai-cyclops.jpl.nasa.gov writes: > I want to define a function that performs a certain computation on its first > invocation and performs a different computation on all subsequent invocations. > Consider the trivial (but representative) example below: > > (defun mutate (list) > (let ((len (length list))) > (prog1 > list > (compile 'mutate > `(lambda () > ,len))))) > > 1> (mutate '(a b c)) > => (a b c) > 2> (mutate '(a b c)) > => Error: too many arguments to function mutate. > 3> (mutate) > => 3 > > My question is, Will this function behave as expected (i.e., as described > above) in any Common LISP? More specifically, is it safe to modify the contents > of a symbols' function cell even as the contents are being executed? I can find > nothing in CLtL2 that addresses this. I welcome all opinions, learned or > otherwise. > > -Len Charest > charest@ai-cyclops.jpl.nasa.gov You could try something like: (defun mutate (list) (let ((len (length list))) (setf (symbol-function 'mutate) #'(lambda () len)) list)) I am not one for altering function definitions on the fly - but if one must, this version seems 'nicer' than the other. I would welcome any comments on it however. -Jenny Rowland jenny.rowland@sait.edu.au