From: Christian Pohlmann
Subject: [newbie question] different behavior in different lisp implementations
Date: 
Message-ID: <pan.2005.12.17.16.57.25.537082@gmail.com>
Hello,

while messing a bit with closures I encountered strange behavior.

I just wrote a closure which holds an one-dimensional array of
length n. The closures "method" 'set takes an array index and
sets the corresponding element to (<index> 0) when called for the
first time on <index>. Subsequent calls increase the second value
of the tuple by 1.

Under GCL and ACL the code works as I, with my 
very primitive knowledge of Lisp, expect.

Anyway, here's the code:
(defun foo (n)
  (let ((arr (make-array n :initial-element nil)))
    (labels ((this (cmd &rest args)
	       (case cmd
		 (set
		  (let ((i (first args)))
		    (if (eq (aref arr i) nil)
			(setf (aref arr i) `(,i 0))
			(incf (second (aref arr i))))))
		 (get arr))))
		 #'this)))

(defun main ()
  (let ((board (foo 4)))
    (funcall board 'set 0)
    (funcall board 'set 1)
    (funcall board 'set 2)
    (funcall board 'set 2)
    (funcall board 'set 3)
    (funcall board 'set 3)
    (funcall board 'get)))

This is what clisp, cmucl and sbcl return:
#((0 2) (1 2) (2 2) (3 2))

This is what gcl and acl return:
#((0 0) (1 0) (2 1) (3 1))

I hope you can tell me, what's going on here.

Regards, Christian

Oh, btw don't wonder about the (labels ((this ...))) construction.
I reduced the closure to its bare essentials. When it was more complex
it needed to call itself. I don't know, if named local functions like
that are common  common lisp  style.

From: ········@comail.ru
Subject: Re: different behavior in different lisp implementations
Date: 
Message-ID: <1134839117.869090.127610@g49g2000cwa.googlegroups.com>
Christian Pohlmann писал(а):

> (defun foo (n)
>   (let ((arr (make-array n :initial-element nil)))
>     (labels ((this (cmd &rest args)
> 	       (case cmd
> 		 (set
> 		  (let ((i (first args)))
> 		    (if (eq (aref arr i) nil)
> 			(setf (aref arr i) `(,i 0))
> 			(incf (second (aref arr i))))))
> 		 (get arr))))
> 		 #'this)))
>
> (defun main ()
>   (let ((board (foo 4)))
>     (funcall board 'set 0)
>     (funcall board 'set 1)
>     (funcall board 'set 2)
>     (funcall board 'set 2)
>     (funcall board 'set 3)
>     (funcall board 'set 3)
>     (funcall board 'get)))
>
> This is what clisp, cmucl and sbcl return:
> #((0 2) (1 2) (2 2) (3 2))

SBCL interprets `(,i 0) as (cons i '(0)), so that tuples share the same
tail ``(0)'':
CL-USER> (let ((b (funcall *b* 'get)))
           (values (eql (aref b 0) (aref b 1))
                   (eql (cdr (aref b 0)) (cdr (aref b 1)))))
NIL ; tuples are different
T     ; but their tails are the same

modification of any of them is visible on all others. Strictly
speaking, it is forbidden by CLHS.
Replace the corresponding sexp with ``(setf (aref arr i) (list i 0))''.

-- 
Regards,
Alexey Dejneka
From: ···············@yahoo.com
Subject: Re: different behavior in different lisp implementations
Date: 
Message-ID: <1134864408.391644.3070@g49g2000cwa.googlegroups.com>
Darn, it's the old problem of modifying a quoted object.  The OP should
know this is a common gotcha.
From: ········@comail.ru
Subject: Re: different behavior in different lisp implementations
Date: 
Message-ID: <1134839152.993386.280500@z14g2000cwz.googlegroups.com>
Christian Pohlmann писал(а):

> (defun foo (n)
>   (let ((arr (make-array n :initial-element nil)))
>     (labels ((this (cmd &rest args)
> 	       (case cmd
> 		 (set
> 		  (let ((i (first args)))
> 		    (if (eq (aref arr i) nil)
> 			(setf (aref arr i) `(,i 0))
> 			(incf (second (aref arr i))))))
> 		 (get arr))))
> 		 #'this)))
>
> (defun main ()
>   (let ((board (foo 4)))
>     (funcall board 'set 0)
>     (funcall board 'set 1)
>     (funcall board 'set 2)
>     (funcall board 'set 2)
>     (funcall board 'set 3)
>     (funcall board 'set 3)
>     (funcall board 'get)))
>
> This is what clisp, cmucl and sbcl return:
> #((0 2) (1 2) (2 2) (3 2))

SBCL interprets `(,i 0) as (cons i '(0)), so that tuples share the same
tail ``(0)'':
CL-USER> (let ((b (funcall *b* 'get)))
           (values (eql (aref b 0) (aref b 1))
                   (eql (cdr (aref b 0)) (cdr (aref b 1)))))
NIL ; tuples are different
T     ; but their tails are the same

modification of any of them is visible on all others. Strictly
speaking, they are literal constants,
so their modification is forbidden by CLHS. Replace the corresponding
sexp with
``(setf (aref arr i) (list i 0))''.

-- 
Regards,
Alexey Dejneka
From: Coby Beck
Subject: Re: [newbie question] different behavior in different lisp implementations
Date: 
Message-ID: <Y3Zof.8429$ic1.3654@edtnps90>
"Christian Pohlmann" <············@gmail.com> wrote in message 
···································@gmail.com...
> Hello,
>
> while messing a bit with closures I encountered strange behavior.
...
> Anyway, here's the code:
> (defun foo (n)
>  (let ((arr (make-array n :initial-element nil)))
>    (labels ((this (cmd &rest args)
>        (case cmd
> (set
>   (let ((i (first args)))
>     (if (eq (aref arr i) nil)
> (setf (aref arr i) `(,i 0))
> (incf (second (aref arr i))))))
> (get arr))))
> #'this)))

Don't quote data that is not intended to remain constant.  Backquote is 
allowed to evaluate to a quoted form, and modifying literal data causes 
undefined behaviour.

Use (list i 0) instead.

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")