Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Emacs Lisp weirdness?

  1. Sep 19, 2008 #1
    First off, I'm using Emacs 22.1.1 on SuSE 10.3 64-bit.

    Now, the thing I've discovered is that in Emacs Lisp, if I do a C-x C-e on this:

    Code (Text):

    (defun annoy ()
      (let ((glorp '("")))
        (setcar glorp (concat (car glorp) "dolphin"))
        (car glorp)))
    and then on (annoy), I get "dolphin", as expected. But then if I do (annoy) again, I get "dolphindolphin" and so on. It keeps building up. Apparently the (let ((glorp '("")))) doesn't clear out glorp, and fails to make it truly local? Or (possibly more likely), that sets glorp to actually point to the list in the code right there, so changing it changes the actual damn code in the function? This makes me upset. Does anyone know what's going on here, and whether this is considered a bug or by design, and (most importantly) how to fix it?

  2. jcsd
  3. Sep 19, 2008 #2


    User Avatar
    Staff Emeritus
    Science Advisor
    Gold Member

    It sounds like correct behavior, and I've seen it in other languages too. You've constructed a list containing a string, and then wrote a function whose job is to take the first element of that list, append "dolphin", and put the result back into the original list.

    You may have intended the construction of a brand new list each time, but you never actually told the program to do that.
  4. Sep 19, 2008 #3
    So you're saying that "let" doesn't create and initialize a local variable? Or that it somehow stores every time it has been used before in a function and only uses the initializer you provided if that particular "let" has never been called before, otherwise using the value it was last set to in that context? Is there something about scoping in ELisp that I'm failing to understand?

    Ok, so if "let" doesn't create and set a local variable, then what is the function to do that?
  5. Sep 19, 2008 #4


    User Avatar
    Staff Emeritus
    Science Advisor
    Gold Member

    As far as I can tell, this is exactly what let does. The problem is that you have instructed it to initialize your local variable to be a reference to a static object and using functions (setcar) that mutate their arguments. (Thus modifying the static object)

    There's a similar situation in old C code that would look like this:

    char* foo()
    char *ptr = "abcde";
    return ptr;

    Repeatedly calling this function would return the strings "bbcde", "cbcde", "dbcde", and so forth. (among other odd behavior) These days, this is illegal C code (although it might still compile), because you're not allowed to mutate string constants. In particular, you really ought not be assigning "abcde" to a nonconstant char pointer.

    It might be the case that you're actually violating the emacs lisp standard by making glorp a reference to a static object, and then mutating that object through setcar -- effectively, you're writing code like

    (setcar '("") "dolphin")

    which is quite silly, unless you intended for '("") to denote a static object.
  6. Sep 19, 2008 #5
    Yikes. So the quote mark doesn't return a copy of the object that comes after it, it actually returns a reference to that immutable object?

    Well that sucks.

    So I guess the right thing to do is to replace every occurrence of '(...) in my program with (copy-sequence '(...)) or something? I certainly hope none of the library functions return references to immutable objects, since writing to constants seems to be a nasty error not caught by the interpreter.
  7. Sep 19, 2008 #6


    User Avatar
    Staff Emeritus
    Science Advisor
    Gold Member

    It's still possible that the observed behavior is intentional and non-buggy (again, I'm operating from a lack of familiarity with lisp semantics) -- it would be akin to the behavior of a static variable in C. I've seen a similar behavior encouraged in python, something like:

    Code (Text):
    def my_function(argument, cache = {}):
       if argument in cache:
          return cache[argument]
       result = perform_lengthy_computation(argument)
       cache[argument] = result
       return result
    In this case, the {} declares an empty associative array, and is only created once, and behaves somewhat like what you're seeing with glorp. Hopefully you're seeing how this feature is being put to good use.

    I can't say what proper lisp style is. But I do observe that setcar breaks the pure functional programming paradigm -- it's a function call that has side-effects (it actually mutates its arguments). My suspicion is that it's probably better to avoid using that. If you can't give up its convenience, you can always make a pure function (hopefully I have the syntax right):

    Code (Text):
    (defun puresetcar (x y) (cons x (cdr y)))
    Though you should probably remove 'set' from the name (i.e. something like "changehead"): looking through the emacs lisp library, names with 'set' in them tend to be functions that mutate their arguments.
    Last edited: Sep 19, 2008
  8. Sep 19, 2008 #7
    Sorry, I'm just not a big devotee of purity. I'm using setcar to pass information back through arguments to a function rather than listing them all up and returning them, because it's more convenient this way for what I'm doing. I know how to write purely functional code, I just see little reason to do so, aside from a sort of little "look what I did" thrill.

    Recursion may or may not be the most mathematically natural way to represent all concepts, but to me, loops seem to be much more natural to the human mind (at least for many things). I can just write the actual steps I would take when doing something, rather than having to sit and puzzle over the most platonic ideal form of the algorithm. Also makes it easier to make changes and identify bugs (just by comparing the code to the steps in my head).
Share this great discussion with others via Reddit, Google+, Twitter, or Facebook