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

Another EQ problem

    Date: 26 May 88 11:01 EST

	    First, let me give Barry Smith (bds@mitre-bedford.ARPA) BIG THANKS
    for posting his "2 Problems" mail with the eq-test program.  It solved a
    bug by analogy, and saved me *much* time and aggravation.
	    I think that the following is a bug that should be changed:
	    I have some code that does surgery (setf's of nth's) on lists in
    a Defstruct.  Since some of the fields are identical, the lists are eq.
    This means (obviously, once you know about it) that if you change slot A,
    slot B is smashed too!
    (defstruct foo
	    (a '(0.0 0.0))
	    (b '(0.0 0.0)))
    ;;compile, then:
    (setf bar (make-foo))
    (setf (nth 0 (foo-a bar)) 4.5)

This is your mistake.  Since the lists were created using quoted
constants you are not permitted to modify them.  For instance, a
compiler is permitted to allocate these lists in read-only memory.

    (foo-a bar)
    -> (4.5 0.0)
    (foo-b bar)
    -> (4.5 0.0)

	    I can understand doing constant folding on let-bound vars, but I'm
    not so sure about struct slots.  The usual fix of changing it to:
    (defstruct foo
	    (a (list 0.0 0.0))
	    (b (list 0.0 0.0)))
    fixes the symptoms -- but I do think it's a bug.

Here's another reason why you shouldn't modify quoted constants.
Evaluate (don't compile) the following:

(setq *foo*
      '(defstruct foo
	 (a '(0.0 0.0))
	 (b '(0.0 0.0))))

(eval *foo*)

(setq bar (make-foo))

(setf (car (foo-a bar)) 4.5)

(eval *foo*)

(foo-a (make-foo)) => (4.5 0.0)

In this case, when we did the SETF, we modified the actual list that was
in the DEFSTRUCT form, so when we evaluated it again we got a different
default value.

The answer comes back to: if you want to be sure that a data structure
doesn't share with another data structure, you MUST call a function that
is guaranteed to construct a fresh data structure.