From: smartnose
Subject: Panic, a strange behavior of lisp program
Date: 
Message-ID: <9542a01a-8e41-47bc-ac48-c75d0736a9ae@r36g2000prf.googlegroups.com>
I type program

(setq list1 '(4 5 3))
(setq list2 '(1))
(setq list1 (union list1 list 2))
(setq list1 (sort list1 '<))

These code runs perfect, but when I checked the value of list2. It's
changed!

(print list2)
5

It seems that common lisp merge the memories of list1 and list2.

Is this what lisp are supposed to do? Shouldn't it return a new list
instead?

I'm confused. Thanks.

From: Tamas K Papp
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <6nkgg6Fm6u8rU1@mid.individual.net>
On Fri, 07 Nov 2008 19:16:38 -0800, smartnose wrote:

> I type program
> 
> (setq list1 '(4 5 3))
> (setq list2 '(1))
> (setq list1 (union list1 list2))

Hint:

(eq (cdddr list1) list2)

so the two lists share structure.  And sort is destructive.

> (setq list1 (sort list1 '<))
> 
> These code runs perfect, but when I checked the value of list2. It's
> changed!

Besides the two lists sharing structure (which I think is not intended), 
the code suffers from a lot of bad style: when you are defining top-level 
special variables, use defparameter (or defvar), and enclose the variable 
names in *'s, eg (defparameter *list1* ...).  A decent implementation 
(like SBCL) will even give you a warning:

* (setq list1 '(4 5 3))

; in: LAMBDA NIL
;     (SETQ LIST1 '(4 5 3))
; 
; caught WARNING:
;   undefined variable: LIST1

; 
; caught WARNING:
;   This variable is undefined:
;     LIST1
; 
; compilation unit finished
;   caught 2 WARNING conditions

(4 5 3)

Also, use setf instead of setq when setting things, it is better style.

I would recommend that you start reading a good Lisp book.  Peter 
Seibel's Practical Common Lisp is available online.

HTH,

Tamas
From: William James
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <gf35fv$dh7$1@aioe.org>
smartnose wrote:

> I type program
> 
> (setq list1 '(4 5 3))
> (setq list2 '(1))
> (setq list1 (union list1 list 2))
> (setq list1 (sort list1 '<))
> 
> These code runs perfect, but when I checked the value of list2. It's
> changed!
> 
> (print list2)
> 5
> 
> It seems that common lisp merge the memories of list1 and list2.
> 
> Is this what lisp are supposed to do? Shouldn't it return a new list
> instead?
> 
> I'm confused. Thanks.

Using Ruby is simpler.

list1 = [4,5,3]
    ==>[4, 5, 3]
list2 = [1]
    ==>[1]
list1 = list1 + list2
    ==>[4, 5, 3, 1]
list1 = list1.sort
    ==>[1, 3, 4, 5]
list2
    ==>[1]
From: Kenny
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <49151d1f$0$4910$607ed4bc@cv.net>
William James wrote:
> smartnose wrote:
> 
> 
>>I type program
>>
>>(setq list1 '(4 5 3))
>>(setq list2 '(1))
>>(setq list1 (union list1 list 2))
>>(setq list1 (sort list1 '<))
>>
>>These code runs perfect, but when I checked the value of list2. It's
>>changed!
>>
>>(print list2)
>>5
>>
>>It seems that common lisp merge the memories of list1 and list2.
>>
>>Is this what lisp are supposed to do? Shouldn't it return a new list
>>instead?
>>
>>I'm confused. Thanks.
> 
> 
> Using Ruby is simpler.
> 
> list1 = [4,5,3]
>     ==>[4, 5, 3]
> list2 = [1]
>     ==>[1]
> list1 = list1 + list2
>     ==>[4, 5, 3, 1]
> list1 = list1.sort
>     ==>[1, 3, 4, 5]
> list2
>     ==>[1]

What if you do not want to copy all the structure because it is copious 
and you know it is not shared? Any way in Ruby to avoid the wasted 
copying? That would be even worse in an interpreted language.

hth,kzo
From: Asgeir
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <20081108134721.38a829b9@sigmund>
Project-Id-Version: Claws-Mail-3.3.1cvs57 (3.4.0)
Report-Msgid-Bugs-To: ····@claws-mail.org
POT-Creation-Date: 2008-06-27 15:06+0100
PO-Revision-Date: 2008-06-23 11:53+0100
Last-Translator: Tristan Chabredier (wwp) <·········@free.fr>
Language-Team:  <······················@dotsrc.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit
Plural-Forms: nplurals=2; plural=n>1;
OMFG

SBCL 1.0.19 (from gentoo-lisp overlay) under Gentoo GNU/Linux gives:

  * (setq list1 '(4 5 3))
  (4 5 3)
  * (setq list2 '(1))
  (1)
  * (setq list1 (union list1 list2))
  (3 5 4 1)
  * (setq list1 (sort list1 '<))
  (1 3 4 5)
  * (print list2)
  (1 3 4 5) 
  (1 3 4 5)

(I've filtred all the warnings like « undefined variable: LIST1 »)

If you try with defparameter and setf, the result is exactly the same
(without the warnings).
WTF ?
-- 
Asgeir
From: Kenny
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <49158fcf$0$4894$607ed4bc@cv.net>
Asgeir wrote:
> Project-Id-Version: Claws-Mail-3.3.1cvs57 (3.4.0)
> Report-Msgid-Bugs-To: ····@claws-mail.org
> POT-Creation-Date: 2008-06-27 15:06+0100
> PO-Revision-Date: 2008-06-23 11:53+0100
> Last-Translator: Tristan Chabredier (wwp) <·········@free.fr>
> Language-Team:  <······················@dotsrc.org>
> MIME-Version: 1.0
> Content-Type: text/plain; charset=iso-8859-1
> Content-Transfer-Encoding: 8bit
> Plural-Forms: nplurals=2; plural=n>1;
> OMFG
> 
> SBCL 1.0.19 (from gentoo-lisp overlay) under Gentoo GNU/Linux gives:
> 
>   * (setq list1 '(4 5 3))
>   (4 5 3)
>   * (setq list2 '(1))
>   (1)
>   * (setq list1 (union list1 list2))
>   (3 5 4 1)
>   * (setq list1 (sort list1 '<))
>   (1 3 4 5)
>   * (print list2)
>   (1 3 4 5) 
>   (1 3 4 5)
> 
> (I've filtred all the warnings like « undefined variable: LIST1 »)
> 
> If you try with defparameter and setf, the result is exactly the same
> (without the warnings).
> WTF ?

The advice you followed was meant to leave room for thought on the part 
of the advisee. The specific style advice you picked up on was just 
style advice not intended to address the surprising result arising from 
inappropriate use of a destructive operation. I was going to say "on 
literals" but I think it would not matter in this case, not that it is 
nice to muck with literals.

hth,kzo
From: smallpond
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <7dd0c455-1e64-472b-8783-3419c5151050@b38g2000prf.googlegroups.com>
On Nov 7, 10:16 pm, smartnose <·········@gmail.com> wrote:
>
> It seems that common lisp merge the memories of list1 and list2.
>
> Is this what lisp are supposed to do? Shouldn't it return a new list
> instead?
>
> I'm confused. Thanks.


You are thinking of variables the way other languages work.

In simple languages, such as ruby, a variable like list2 is an area
of
memory which contains a value.  list2 owns that memory.  In lisp,
list2 is a view of a list which is not owned by anyone and may have
multiple viewers.

union doesn't take N lists and return a new list, it returns a new
view of memory, creating as few new cons cells as needed.  After the
union, list1 and list2 still have the same views, but you are
discarding old list1 in favor of the new view, which includes the
view of list2.  sort also doesn't create new cells, it rearranges the
existing ones.  list2 isn't changing, the list that it views is being
changed.

Don't think of list functions as acting on variables, think of them
as acting on lists which are separate things.
From: Ari Johnson
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <m2hc6inh6a.fsf@hermes.theari.com>
smallpond <·········@juno.com> writes:

> Don't think of list functions as acting on variables, think of them
> as acting on lists which are separate things.

Main lesson: Common Lisp is not a functional language.  It has many
destructive operators that were included for the sake of optimization,
both of the programmer's time and of running time.

Corollary and specific lesson: If you see unexpected behavior, look up
the operators that seem to be at fault in the Hyperspec and look for
phrases like "permitted to modify" or "destructively."  For instance,
the entry for UNION and NUNION says that the latter is permitted to
modify the lists.  The entry for SORT says it will destructively sort
its input.
From: Raffael Cavallaro
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <gf545d$r4u$1@aioe.org>
On 2008-11-08 14:36:45 -0500, Ari Johnson <·········@gmail.com> said:

> Corollary and specific lesson: If you see unexpected behavior, look up
> the operators that seem to be at fault in the Hyperspec and look for
> phrases like "permitted to modify" or "destructively."  For instance,
> the entry for UNION and NUNION says that the latter is permitted to
> modify the lists.  The entry for SORT says it will destructively sort
> its input.

finally, just in case it isn't already obvious, you can turn 
destructive functions into side-effect free versions by copying the 
inputs before passing them to the destructive function.
From: smartnose
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <0acd0778-877b-4133-857a-20bb60a42723@u29g2000pro.googlegroups.com>
Well, folks. I reeeeally appreciate your help.

Scary lisp.

W.

On Nov 8, 5:34 pm, Raffael Cavallaro <················@pas-d'espam-
s'il-vous-plait-mac.com> wrote:
> On 2008-11-08 14:36:45 -0500, Ari Johnson <·········@gmail.com> said:
>
> > Corollary and specific lesson: If you see unexpected behavior, look up
> > the operators that seem to be at fault in the Hyperspec and look for
> > phrases like "permitted to modify" or "destructively."  For instance,
> > the entry for UNION and NUNION says that the latter is permitted to
> > modify the lists.  The entry for SORT says it will destructively sort
> > its input.
>
> finally, just in case it isn't already obvious, you can turn
> destructive functions into side-effect free versions by copying the
> inputs before passing them to the destructive function.
From: Kenny
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <4916ee7e$0$4910$607ed4bc@cv.net>
smartnose wrote:
> Well, folks. I reeeeally appreciate your help.
> 
> Scary lisp.

Wait until you delete a method, do a full recompile, and see it printing 
output to the listener the next time you run.

Ooooooooooooo!!!!!

Oh, and (eq (+ 2 2) 4) -> nil?

Ayyyyyyyyyyyy!!!!!

hth, kzo
From: Raffael Cavallaro
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <gf6ss8$q0k$1@aioe.org>
On 2008-11-09 09:05:55 -0500, Kenny <·········@gmail.com> said:

> smartnose wrote:
>> Well, folks. I reeeeally appreciate your help.
>> 
>> Scary lisp.
> 
> Wait until you delete a method, do a full recompile, and see it 
> printing output to the listener the next time you run.
> 
> Ooooooooooooo!!!!!
> 
> Oh, and (eq (+ 2 2) 4) -> nil?
> 
> Ayyyyyyyyyyyy!!!!!

am I too late for halloween...

? (let* ((*read-base* (1+ (1+ *read-base*)))
         (*print-base* *read-base*)
         (ten (read-from-string "10"))
         (scary-lisp (* ten ten (1- ten))))
    (print scary-lisp))

B00
1584
From: William James
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <gf79up$rbe$1@aioe.org>
Raffael Cavallaro wrote:

> On 2008-11-09 09:05:55 -0500, Kenny <·········@gmail.com> said:
> 
> > smartnose wrote:
> > > Well, folks. I reeeeally appreciate your help.
> > > 
> > > Scary lisp.
> > 
> > Wait until you delete a method, do a full recompile, and see it
> > printing output to the listener the next time you run.
> > 
> > Ooooooooooooo!!!!!
> > 
> >Oh, and (eq (+ 2 2) 4) -> nil?
> > 
> > Ayyyyyyyyyyyy!!!!!
> 
> am I too late for halloween...
> 
> ? (let* ((*read-base* (1+ (1+ *read-base*)))
>         (*print-base* *read-base*)
>         (ten (read-from-string "10"))
>         (scary-lisp (* ten ten (1- ten))))
>    (print scary-lisp))
> 
> B00
> 1584

Forth:

12 base !  ok
10 10 10 1- * *  ok
dup . cr B00
 ok
decimal . 1584  ok
From: Kaz Kylheku
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <20081109191855.61@gmail.com>
On 2008-11-08, smartnose <·········@gmail.com> wrote:
> It seems that common lisp merge the memories of list1 and list2.
>
> Is this what lisp are supposed to do? Shouldn't it return a new list
> instead?

That would be a requirement in a purely functional language, which fortunately
Lisp isn't.

Returning a new list is elegant from a theoretical viewpoint but impractical
from an engineering viewpoint. Lisp doesn't sacrifice either viewpoint, by
giving you a choice. The engineering viewpoint is much more important.
Usually whenever there is a conflict between good engineering and theoretical
elegance, good engineering should win.

A non-destructive sort is wasteful. You want to instruct the machine to arrange
data in order, but it does a whole lot  of extra work to allocate space for a
full copy of it. Having no way to prevent this waste is unacceptable.

You can construct a non-destructive list sort from the destructive one easily;
simpy use COPY-LIST to duplicate the list structure. E.g.

  (defun sort-list (list function)
    (sort (copy-list list) function))

But you cannot construct a destructve list from a non-destructive one!
The inherent copying is a behavior that is encapsulated in the non-destructive
funtion.

If you're designing a general-purpose programming language API and are
providing only one sort routine, the best engineering decision is that it
should be destructive.

Numerous Lisp functions come in destructive and non-destructive flavors. For
instance APPEND joins lists non-destructively, and NCONC does the same thing,
but destructively.

Often, judicious use of the destructive functions can improve the efficiency of
code without doing anything to occlude its clarity.
From: Pascal J. Bourguignon
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <7cd4h4j5a0.fsf@pbourguignon.anevia.com>
smartnose <·········@gmail.com> writes:

> I type program
>
> (setq list1 '(4 5 3))
> (setq list2 '(1))
> (setq list1 (union list1 list 2))
> (setq list1 (sort list1 '<))
>
> These code runs perfect, but when I checked the value of list2. It's
> changed!
>
> (print list2)
> 5
>
> It seems that common lisp merge the memories of list1 and list2.
>
> Is this what lisp are supposed to do? Shouldn't it return a new list
> instead?
>
> I'm confused. Thanks.

In summary, 

UNION may return a list that shares structure with either or both the
lists refered to by list1 or list2.

SORT may (and most probably will) modify the list refered to by list1,
that is, the list returned by UNION which may share structure with the
literal lists (4 5 3) or (1).

Modifying literal data is not defined, your program is not conformant,
and you shouldn't be surprised if something strange happens. 



In any case, the _value_ of list2 is NOT changed:

C/USER[223]> (let ((list1 (list 4 5 3))
                   (list2  (list 1)))

                (let ((backup-list2 list2))

                  (setq list1 (union list1 list2))
                  (setq list1 (sort list1 '<))

                  (assert (eq list2 backup-list2))

                  (print list1)
                  (print list2)
                  (values)))


(1 3 4 5) 
(5) 

C/USER[224]> 

The _value_ of list2 is a reference to a CONS cell.  This CONS cell
contained originally the number 1 in its CAR, and the symbol NIL in
its CDR.  SORT changed the CAR of THIS CONS cell, but didn't change
the value of list2.




See the other answers, and read the CLHS for the details.

-- 
__Pascal Bourguignon__
From: Robert Maas, http://tinyurl.com/uh3t
Subject: Panic, a strange behavior of lisp program
Date: 
Message-ID: <REM-2008nov12-001@Yahoo.Com>
> From: smartnose <·········@gmail.com>
> I type program
> (setq list1 '(4 5 3))
> (setq list2 '(1))
> (setq list1 (union list1 list2))
> (setq list1 (sort list1 '<))
(I fixed the obvious typo where you had a space between list and 2.)

That's not legal Common Lisp, because the initial values of list1
and list2 are quoted constants which are *never* supposed to be
changed, and after calling UNION there is structure sharing between
that constant value of list2 and the return value, and after the
setq there's shared structure between the new value of list1 and
the constant value of list2, and then you try to do sort which is a
destructive operation which is not allowed for constant values.

I wish that all Lisp implementations would *enforce* constant
structures. For example, when the read-eval-print loop gets
 (setq list2 '(1))
after it expands the reader macro to get
 (setq list2 (quote (1)))
when is recursively evaluating that form, at the point where it is
ready to evaluate the sub-form (quote (1)), it should unpurify a
pure page, copy (1) to that page, re-purify it, discard the
original copy of (1) or let the GC deal with it later. Then later
when SORT is called with a parameter that includes some that (1)
structure on a pure page, and SORT tries to modify it, an exception
would be thrown something like:
 Attempt to modify data on pure page,
 specifically attempt to do RPLACD on constant value (1),
 called from (sort list1 '<))
Then you'd know right there that your code was wrong.

Now there are two ways to fix *that* problem, one of which is to
"fix" it wrongly by satifying the literal spec but not fixing the
bug you reported:
  (setq list1 (list 4 5 3))
  (setq list2 (list 1))
  (setq list1 (union list1 list2))
  (setq list1 (sort list1 '<))
the other of which is to *really* fix the bug:
  (setq list1 '(4 5 3))
  (setq list2 '(1))
  (setq list1 (union list1 list2))
  (setq list1 (sort (copy-list list1) '<))

Referring back to the original non-CL code:
> These code runs perfect,

Given that your original code wasn't valid CL in the first place,
it's impossible for it to run perfectly. At best one of two things
happened:
- You got an error that you were trying to modify read-only
   (constant) data, which is what I said I wish would happen, but
   no this isn't what happened to you;
- The CL implementation violated CL assumptions by modifying
   constant data thereby postponing feedback to you that you had
   done something wrong. That's what really happened. It's sorta
   like you run a red light, and no cop stops you, so you think you
   got by with it, then weeks later you get a ticket in the mail
   saying that you are being fined $300 for breaking the law, as
   proven by an automated camera. OK, I'm exaggerating a little,
   but still I like the idea of getting an error the moment I try
   to do something that isn't even valid Common Lisp, rather than
   have the implementation do something illegal and I don't find
   out until later.

> but when I checked the value of list2. It's changed!

Yeah, because your implementation didn't respect the fact that a
quoted list is supposed to be ***constant***, not possible to be
changed by subsequent program operations such as your call to SORT.

> (print list2)
> 5

Now *that* really doesn't make sense. If the implementation
performs SORT by doing RPLACD to re-link cells, then I would expect
that the value of list2 might be (1 3 4 5) now. Or if the
implementation performs SORT by doing RPLACA to replace single
elements while keeping the chain of CONS cells unchanged, then I
would expect the value of list2 might be (5). Are you sure the
latter isn't what you meant, like you omitted the parens around 5
when posting?

> It seems that common lisp merge the memories of list1 and list2.

Yes. UNION is allowed to share list structure with either/both of
the original lists if it means less CONSing. What it's *not*
allowed to do is modify either (to avoid all CONSing whatsoever)
use NUNION if you want that.

> Is this what lisp are supposed to do? Shouldn't it return a new
> list instead?

If you're asking about UNION, read the spec where it clearly says
that sharing of structure is possible. No actually although CLtL
clearly says that, the CL HyperSpec doesn't say that, it only says
that the result may be EQ to either of the parameters, it doesn't
say that any other sharing may be possible. Kent, please comment on
this apparent mistake in conversion from CLtL to ANSI-CL. Did I
mis-read the HyperSpec, or was a mistake made between ANSI-CL and
CLHS, or was a mistake made between CLtL and ANSI-CL, or did I
mis-read CLtL? If the mistake is from CLtL to ANSI-CL, is there a
Web page that lists all such "obvious" mistakes. In your opinion,
should CL implementations conform to strict ANSI-CL in cases like
this, thereby going along with that error, or should CL
implemetations revert to obeying CLtL specification, thereby
avoiding the mistake?

> I'm confused.

And your implementation of CL, which failed to signal an error when
you destructively modified some constant structure by calling SORT
on a shared structure, helped to confuse you.
From: Pascal J. Bourguignon
Subject: Re: Panic, a strange behavior of lisp program
Date: 
Message-ID: <87myg41un4.fsf@hubble.informatimago.com>
·············@teh.intarweb.org (Robert Maas, http://tinyurl.com/uh3t) writes:

> I wish that all Lisp implementations would *enforce* constant
> structures. 

Don't wish, do it yourself!  You've got the sources.

For example, clisp can be compiled with an option adding 32-bit to all
lisp objects.  You could use one bit to indicate a read-only cons
cell.  You would only have to patch clisp source to add to rplaca and
rplacd, and a few other primitives to set vectors, arrays, hash-tables
and structures, (and that's about all the mutable and readable objects
we have IIRC), a test for read-only object, and to add to quote the
setting of this bit to each of these objects in its argument.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we. -- Georges W. Bush