From: Adam Warner
Subject: The final piece of the puzzle: Assignment
Date: 
Message-ID: <pan.2003.02.25.09.18.28.890715@consulting.net.nz>
It's now all beautifully clear (I hope). If you don't believe what I'm
saying then at least first read pages 314-315 of David S. Touretzky's
"Common Lisp: A Gentle Introduction to Symbolic Computation":
http://www-2.cs.cmu.edu/~dst/LispBook/

Variables contain a POINTER to the OBJECT that is its VALUE. Assigning the
value of 3 to a variable means that the variable contains a POINTER to an
OBJECT with VALUE 3.

Consider this assignment of x and y: (setf x 3) (setf y x) assigns x a
POINTER to an OBJECT with VALUE 3 and assigns y a POINTER to an OBJECT
with VALUE 3. Ordinarily we might expect these to be the SAME OBJECT. Yet
we (I) now understand that Common Lisp does not mandate this and numbers
and characters may be copied at any time. Thus y may end up containing a
POINTER to a DIFFERENT OBJECT with VALUE 3.

(let ((x 5)) (eq x x)): x is bound to a POINTER to an OBJECT with VALUE 5.
Common Lisp implementations are free to copy this object at any time. If
this happens there will be POINTERS OF DIFFERENT VALUES to DIFFERENT
OBJECTS with VALUE 5, and (eq x x) will return false.

Touretzky provides a good description of what incrementing a variable
actually means in Lisp. The value of the variable is not directly
incremented. Rather the variable's POINTER is replaced with a POINTER to a
DIFFERENT OBJECT with the required VALUE (1+ the original value). (eql 3
4) is false because the pointers to the objects containing values 3 and 4
necessarily describe different locations.

Once I come to understand that everything in Lisp is a pointer then what
happens with destructive modification isn't a surprise. For example:

* (setf x (copy-seq "a string literal"))                                     

"a string literal"
* (setf y x)                            

"a string literal"
* (setf (aref x 0) #\A) 

#\A
* x                    

"A string literal"
* y

"A string literal"

x is assigned a pointer to a mutable string object. y is assigned the same
pointer value. It is no surprise that when the object x points to is
modified that y's returned value changes, because y points to the same
object (and x and y continue to be EQ).

The lesson is that EVERYTHING IN LISP IS A POINTER. And this is confirmed
by Kent M. Pitman (who makes an additional valuable point that every
object is indirect so pointers only need be mentioned for emphasis):
http://groups.google.com/groups?selm=sfw3e4wg6qx.fsf%40world.std.com

It's possible to explain the above example without referring to pointers.
To do so one explains that x is assigned to a mutable string object. And y
is assigned to the same object. When x changes y changes because they are
different symbolic names for the same object.

Regards,
Adam

From: Jochen Schmidt
Subject: Re: The final piece of the puzzle: Assignment
Date: 
Message-ID: <b3fdl4$a2s$07$1@news.t-online.com>
Adam Warner wrote:
[snipped explanation]

While your investigations are indeed true - you have to remember that 
"pointer" in this context is a different thing what it is in for example C.

A "pointer" to the fixnum 3 can be the following number in binary format

#*00000000000000000000000000001100

The lowest 3 bits are then used to encode that this is an immediately 
accessible odd fixnum. It is obviously clear that such a "pointer" does not 
have anything to do with physical addresses.

Even "lisp-pointers" which denote non-immediate data (like functions) are 
not represented as normal physical addresses but need to get shifted first.

I personally prefer calling it "object-references" instead of simply 
"pointers" because one easily confuses people when talking about "pointers" 
(C) and "pointers" (Lisp) at the same time.

ciao,
Jochen
From: Rob Warnock
Subject: Re: The final piece of the puzzle: Assignment
Date: 
Message-ID: <htucnQrkh6ZEyMajXTWc-w@speakeasy.net>
Jochen Schmidt  <···@dataheaven.de> wrote:
+---------------
| I personally prefer calling it "object-references" instead of simply 
| "pointers" because one easily confuses people when talking about "pointers" 
| (C) and "pointers" (Lisp) at the same time.
+---------------

When trying to avoid "pointer", I usually talk about "object identifiers"
rather than "object references", since the latter still has substantial
pointer connotations to it. (IMHO.)

Also remember that there have been implementations of GC'd languages in
the past -- classic Smalltalk comes to mind -- where the object identifiers
were *NOT* pointers at all, but fairly-small indices into a global "object
table" (which then may or may not have contained pointers to objects too
large to fit in an object table slot). This allowed large objects to be
moved during GC compaction *without* changing the values of their object
identifiers held in variables or in other objects.

But I agree that for tutorial purposes in Lisp & other languages with
a copying GC, terms like "object identifier" or "object reference" or
"object cookie" (whatever) are probably better than "pointer".

(Even though in most Lisps the object identifiers do usually look an
awful lot like pointers... except for immediates, of course!)  ;-}


-Rob

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Barry Margolin
Subject: Re: The final piece of the puzzle: Assignment
Date: 
Message-ID: <7pM6a.3$tk4.69@paloalto-snr1.gtei.net>
In article <······················@speakeasy.net>,
Rob Warnock <····@rpw3.org> wrote:
>Also remember that there have been implementations of GC'd languages in
>the past -- classic Smalltalk comes to mind -- where the object identifiers
>were *NOT* pointers at all, but fairly-small indices into a global "object
>table"

Isn't that what an address is?  In this case, the "global object table" is
all of memory.

At the conceptual level, these things are all isomorphic.

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Rob Warnock
Subject: Re: The final piece of the puzzle: Assignment
Date: 
Message-ID: <zP2cnU8rsY2VE8GjXTWc-g@speakeasy.net>
Barry Margolin  <··············@level3.com> wrote:
+---------------
| Rob Warnock <····@rpw3.org> wrote:
| >Also remember that there have been implementations of GC'd languages in
| >the past -- classic Smalltalk comes to mind -- where the object identifiers
| >were *NOT* pointers at all, but fairly-small indices into a global "object
| >table"
| 
| Isn't that what an address is?  In this case, the "global object table" is
| all of memory.
| 
| At the conceptual level, these things are all isomorphic.
+---------------

Well, you've introduced yet another term -- "conceptual level" -- that
needs to be more precisely defined before I can know whether or not I
agree with you!  ;-}  ;-}

But what I was trying to point out was that (1) the things that EQ
compares need not be "machine addresses" even for heap-allocated
objects, and (2) that you can have a compacting garbage collector
that does *not* need to re-write the object identifier values held
in variables or other objects when the designated object is moved
around in machine memory. I.e., in such a system the machine address
of an object can change *without* its object identifier (or whatever
you want to call such a thing) changing.

Viewed at the level of writing such a GC, or of writing, say, C code
that has to access Lisp objects, address-based Lisp values and OID-based
Lisp values are not *quite* isomorphic. Certainly not in terms of
performance (which, by the way, can go *either* way, if you consider
sufficiently perverted test cases).

But maybe I'm quibbling...


-Rob

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Adam Warner
Subject: Re: The final piece of the puzzle: Assignment
Date: 
Message-ID: <pan.2003.02.25.10.00.55.580324@consulting.net.nz>
Hi Jochen Schmidt,

> Adam Warner wrote:
> [snipped explanation]
> 
> While your investigations are indeed true - you have to remember that
> "pointer" in this context is a different thing what it is in for example
> C.
> 
> A "pointer" to the fixnum 3 can be the following number in binary format
> 
> #*00000000000000000000000000001100
> 
> The lowest 3 bits are then used to encode that this is an immediately
> accessible odd fixnum. It is obviously clear that such a "pointer" does
> not have anything to do with physical addresses.
> 
> Even "lisp-pointers" which denote non-immediate data (like functions)
> are not represented as normal physical addresses but need to get shifted
> first.
> 
> I personally prefer calling it "object-references" instead of simply
> "pointers" because one easily confuses people when talking about
> "pointers" (C) and "pointers" (Lisp) at the same time.

Thanks for the clarification! Is it possible yourself or someone can
explain how copying a number or character object can lead to "tremendous
performance improvements"?

Regards,
Adam
From: Jochen Schmidt
Subject: Re: The final piece of the puzzle: Assignment
Date: 
Message-ID: <b3ff60$uc$00$2@news.t-online.com>
Adam Warner wrote:

> Thanks for the clarification! Is it possible yourself or someone can
> explain how copying a number or character object can lead to "tremendous
> performance improvements"?

Think of bignums and computations involving them.

ciao,
Jochen
From: Tim Bradshaw
Subject: Re: The final piece of the puzzle: Assignment
Date: 
Message-ID: <ey3wujoh5kq.fsf@cley.com>
* Adam Warner wrote:

> It's possible to explain the above example without referring to pointers.
> To do so one explains that x is assigned to a mutable string object. And y
> is assigned to the same object. When x changes y changes because they are
> different symbolic names for the same object.

And it's much clearer, too.  Just think in terms of objects with
identity and remember that numbers and characters have special
exceptions made for them...

--tim