From: ·······@ziplip.com
Subject: totally baffled
Date: 
Message-ID: <MILZMNF5CKGLKAPULYLRGOLRFZKCJQFRFRL2FYKH@ziplip.com>
(defun ++ (x) 
  (incf x))

I was 110% sure that

(let ((loc 1))
  (++ loc)
  loc)

would return 2, but it returned 1. Using INCF instead of ++
returns 2. Doesn't Lisp pass by reference?

Let's see

(defun ++second (x)
  (incf (second x)))

(let ((loc '(0 1)))
  (++second loc)
  (second loc))

Yep.

From: Matthew Danish
Subject: Re: totally baffled
Date: 
Message-ID: <20030817035818.GT17568@lain.mapcar.org>
On Sat, Aug 16, 2003 at 08:29:38PM -0700, ·······@ziplip.com wrote:
> Doesn't Lisp pass by reference?

No, it is call-by-value.

> Let's see
> 
> (defun ++second (x)
>   (incf (second x)))
> 
> (let ((loc '(0 1)))
>   (++second loc)
>   (second loc))
> 
> Yep.

Nope, you have a layer of indirection here.

Let's take this step by step:

  (++second loc) ;; look up the value of loc and pass it to ++second
  ;; in ++second
    (defun ++second (x) ;; bind x to the first argument
      (incf (second x)) ;; increment the second number in the list
      ;; return the new number
  ;; meanwhile, back in the original let
  ;; the VALUE, bound to the VARIABLE loc, has been modified by ++second.
  ;; the second element of it was changed, destructively, to 2
  ;; therefore, 
  (second loc) ;; => 2

You need to distinguish between variables and values.  Variables are
bound to values.  When variables are evaluated, they evalute to their
value.  That value might be given to a function; the function then binds
that value to a variable of its own--a completely different variable
than the one before.  If you then perform an operation that sets the
binding of the function's variable to another value, why should it
affect the original variable?  (incf x) is one such operation.  It
expands to, essentially, (setf x (1+ x)).  Now the variable x is bound 
to a new value. 

Think about this:

(let* ((x 1) (y x))
  (incf x)
  y)

Does it make sense for y to change its value?  NO!  Because y has been
bound to the VALUE OF x (at that point in time), NOT the variable x.

-- 
; Matthew Danish <·······@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
From: Peter Seibel
Subject: Re: totally baffled
Date: 
Message-ID: <m34r0hszi2.fsf@javamonkey.com>
········@ziplip.com" <·······@ziplip.com> writes:

> (defun ++ (x) 
>   (incf x))
> 
> I was 110% sure that
> 
> (let ((loc 1))
>   (++ loc)
>   loc)
> 
> would return 2, but it returned 1. Using INCF instead of ++
> returns 2. Doesn't Lisp pass by reference?

Yes it does.[1] But INCF doesn't modify the object it is passed. In
fact it can,t because number objects are immutable. Rather, it
manipulates a generalized "place", of which variables are the simplest
and most common example.

> Let's see
> 
> (defun ++second (x)
>   (incf (second x)))
> 
> (let ((loc '(0 1)))
>   (++second loc)
>   (second loc))

This works[2] because (second foo) is another kind of "place". Which
is possible because a list[3] is mutable.

-Peter

[1] Well, numbers and character objects are allowed to be copied at
any time but that doesn't matter here because they are immutable
objects. But I don't want the Guru's to beat me up about this.

[2] Technically the behavor of this code is undefined but only because
you passed a literal list '(0 1). If you want to diddle a list you
need to make a new list at runtime: (list 0 1).

[3] Or, if you like, the underlying cons cells. (Hi Kenny!)
-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Peter Seibel
Subject: Re: totally baffled
Date: 
Message-ID: <m3y8xssy97.fsf@javamonkey.com>
Peter Seibel <·····@javamonkey.com> writes:

> ········@ziplip.com" <·······@ziplip.com> writes:
> 
> > (defun ++ (x) 
> >   (incf x))
> > 
> > I was 110% sure that
> > 
> > (let ((loc 1))
> >   (++ loc)
> >   loc)
> > 
> > would return 2, but it returned 1. Using INCF instead of ++
> > returns 2. Doesn't Lisp pass by reference?
> 
> Yes it does.

Actually, that may have been hasty. Since another poster just told you
it's call-by-value I should probably explain myself better. When a
function is called the arguments are evaluated and the resulting
*values* are indeed passed to the function. However the *value* of
most objects is best thought of as a "pointer" or "reference" to the
memory represeting the object. If the object is mutable, changes to
that object will be visible to the caller (and to anyone else who has
a refence to that same object. For example, a cons cells, as created
by CONS, is a simple mutable object that can contain references to two
other objects. The functions RPLACA and RPLACD each mutate one of
those references. Thus:

  (defun mutate-cons-cell (cons new-car new-cdr)
    (rplaca cons new-car)  ;; or (setf (car cons) new-car)
    (rplacd cons new-cdr)) ;; or (setf (cdr cons) new-cdr)

is a function that changes the CAR and CDR of the passed in cons cell.
Thus this function, which creates a new cons cell and passes it to
mutate-cons-cell:

  (defun foo () 
    (let ((my-cons (cons 0 1)))
      (format t "car: ~a; cdr: ~a~%" (car my-cons) (cdr my-cons))
      (mutate-cons-cell my-cons 1 2)
      (format t "car: ~a; cdr: ~a~%" (car my-cons) (cdr my-cons))))

prints this:

  CL-USER(10): (foo)
  car: 0; cdr: 1
  car: 1; cdr: 2
  NIL

because the variable MY-CONS in FOO is a reference to the same object
that was passed to MUTATE-CONS-CELL and subsequently mutated.

However, there's no way for a function to change the value a
*variable* in its caller. This function, is a no-op (except that it
creates a cons cell that becomes garbage as soon as it returns):

  (defun useless (cons new-car new-cdr)
    (setf cons (cons new-car new-cdr)))

Called by this function:

  (defun bar () 
    (let ((my-cons (cons 0 1)))
      (format t "car: ~a; cdr: ~a~%" (car my-cons) (cdr my-cons))
      (useless my-cons 1 2)
      (format t "car: ~a; cdr: ~a~%" (car my-cons) (cdr my-cons))))

it prints this:

  CL-USER(13): (bar)
  car: 0; cdr: 1
  car: 0; cdr: 1
  NIL

One interpretation of call-by-reference would mean that USELESS could
change the value of the variable MY-CONS in BAR. Which is not the case
in Common Lisp. On the other hand, some folks would understand
call-by-value to mean that a *copy* of the object is passed. If that
were true, then MUTATE-CONS-CELL wouldn't have any effect on the cons
cell refered to by MY-CONS in FOO because it would be mutating a copy.
Which is also *not* what happens in Common Lisp. And which is why I
originally said Lisp is call-by-reference. But that was sloppy. Sorry.

So, Lisp is probably best described as call-by-value but the values
are "pointers", "references", or "handles" to objects that have a
unique identity. (At least one of this groups gurus has, in past
discussions of this topic, eschewed both the terms call-by-value and
call-by-reference, prefering, I believe, his on coinage,
call-by-identity. There's some sense in that.)

Anyway, the point here is not that what happens is complicated--it's
quite simple once you understand the distinction between variables and
objects; it's the terminology that's confusing. At least that's my
problem. ;-)

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Kenny Tilton
Subject: Re: totally baffled
Date: 
Message-ID: <3F3F0ACD.8080206@nyc.rr.com>
Peter Seibel wrote:
> ········@ziplip.com" <·······@ziplip.com> writes:
> 
> 
>>(defun ++ (x) 
>>  (incf x))
>>
>>I was 110% sure that
>>
>>(let ((loc 1))
>>  (++ loc)
>>  loc)
>>
>>would return 2, but it returned 1. Using INCF instead of ++
>>returns 2. Doesn't Lisp pass by reference?
> 
> 
> Yes it does.[1] 

Huge thread on this recently. Duane Rettig, IIRC, prefers "call by Lisp 
value" since comparison with other languages is a little applesy-orangesy.

> But INCF doesn't modify the object it is passed.

It sure as hell tries:

CELLO(1): (incf 1)
Error: 1 illegal atomic form for get-setf-expansion.
[condition type: PROGRAM-ERROR]

It's a macro:

CELLO(3): (macroexpand-1 '(incf x))
(SETQ X (+ X 1))


> 
> [3] Or, if you like, the underlying cons cells. (Hi Kenny!)

______
| Hi |
------
      |
      V
      _________
      | Peter |
      ---------
              |
              V



-- 

  kenny tilton
  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"Career highlights? I had two. I got an intentional walk from
Sandy Koufax and I got out of a rundown against the Mets."
                                                  -- Bob Uecker
From: Frode Vatvedt Fjeld
Subject: Re: totally baffled
Date: 
Message-ID: <2hr83k4nqh.fsf@vserver.cs.uit.no>
Peter Seibel wrote:

>> But INCF doesn't modify the object it is passed.

Kenny Tilton <·······@nyc.rr.com> writes:

> It sure as hell tries:
>
> CELLO(1): (incf 1)
> Error: 1 illegal atomic form for get-setf-expansion.
> [condition type: PROGRAM-ERROR]

It's meaningless to say that incf tries to modify the object it is
passed, because it's impossible to pass an object as such to
incf. Incf accepts a "place" as its argument, not an object.

A better error desrcription would have been "1 is not a place."

-- 
Frode Vatvedt Fjeld
From: Kenny Tilton
Subject: Re: totally baffled
Date: 
Message-ID: <3F3F72BE.8070200@nyc.rr.com>
Frode Vatvedt Fjeld wrote:
> Peter Seibel wrote:
> 
> 
>>>But INCF doesn't modify the object it is passed.
>>
> 
> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> 
>>It sure as hell tries:
>>
>>CELLO(1): (incf 1)
>>Error: 1 illegal atomic form for get-setf-expansion.
>>[condition type: PROGRAM-ERROR]
> 
> 
> It's meaningless to say that incf tries to modify the object it is
> passed, because it's impossible to pass an object as such to
> incf. Incf accepts a "place" as its argument, not an object.

I did not want to complicate things by dragging in the idea that, since 
incf is a macro, one might think of the "passing" as being done at 
compile-time, with a form being the object passed. And yer right, ACL is 
not trying to modify that form, it is trying to expand it into code 
which will setf some place. Somewhere.

> 
> A better error desrcription would have been "1 is not a place."
> 

Not bad. maybe they should have said both. the nice thing about the ACL 
error is that it says precisely where things went wrong on its side, so 
I have a better idea of precisely what I left out (the setter I meant to 
have written). Your error is good because it rises above the literal 
issue to a higher-level view of what went wrong (the user does not know 
incf must be used on places). But then it is guessing.

-- 

  kenny tilton
  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"Career highlights? I had two. I got an intentional walk from
Sandy Koufax and I got out of a rundown against the Mets."
                                                  -- Bob Uecker
From: Hartmann Schaffer
Subject: Re: totally baffled
Date: 
Message-ID: <3f3f42ef@news.sentex.net>
In article <········································@ziplip.com>,
	········@ziplip.com" <·······@ziplip.com> writes:
> (defun ++ (x) 
>   (incf x))
> 
> I was 110% sure that
> 
> (let ((loc 1))
>   (++ loc)
>   loc)
> 
> would return 2, but it returned 1.

lisp passes by value, so incf increments the copym and loc remains
unchanged

> Using INCF instead of ++
> returns 2. Doesn't Lisp pass by reference?

no

> Let's see
> 
> (defun ++second (x)
>   (incf (second x)))
> 
> (let ((loc '(0 1)))
>   (++second loc)
>   (second loc))
> 
> Yep.

ok. in this case you pass (a ponter to the) list and increase its
second element.  yep

hs

-- 

ceterum censeo SCO esse delendam
From: Kenny Tilton
Subject: Re: totally baffled
Date: 
Message-ID: <3F3F0BDE.8050702@nyc.rr.com>
·······@ziplip.com wrote:
> (defun ++ (x) 
>   (incf x))
> 
> I was 110% sure that
> 
> (let ((loc 1))
>   (++ loc)
>   loc)
> 
> would return 2, but it returned 1. Using INCF instead of ++
> returns 2. Doesn't Lisp pass by reference?
> 
> Let's see
> 
> (defun ++second (x)
>   (incf (second x)))
> 
> (let ((loc '(0 1)))
>   (++second loc)
>   (second loc))
> 
> Yep.

Now you know why we are so angry.

-- 

  kenny tilton
  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"Career highlights? I had two. I got an intentional walk from
Sandy Koufax and I got out of a rundown against the Mets."
                                                  -- Bob Uecker
From: Kaz Kylheku
Subject: Re: totally baffled
Date: 
Message-ID: <cf333042.0308180956.1aac5fc8@posting.google.com>
········@ziplip.com" <·······@ziplip.com> wrote in message news:<········································@ziplip.com>...
> (defun ++ (x) 
>   (incf x))
> 
> I was 110% sure that
> 
> (let ((loc 1))
>   (++ loc)
>   loc)
> 
> would return 2, but it returned 1. Using INCF instead of ++
> returns 2. Doesn't Lisp pass by reference?

Lisp function calls pass around values which are references to
objects, or in some cases, they are bit patterns that actually contain
that value (typically the case with small integers which are called
fixnums).

But that is irrelevant here. Neither pass by value nor pass by
reference will allow you to write INCF as a function. Because you see
INCF does not work on the value that is being passed; it works by
binding the place to a new value.

INCF is an operator that works using ``call by name'' rather than
``call by reference'' or ``call by value''. Call by name means that
the operator receives the code of the *expression* which designates,
or names the place where the object is stored. So that when you write
(INCF (THIRD LIST)) the argument to INCF is not the value of (THIRD
LIST) nor a reference to where it is stored. The argument is the
(THIRD LIST) expression itself: its source code! The INCF operator has
to analyze the (THIRD LIST) expression and synthesize code which reads
the value of the third element of the list, computes a new value and
stores it back.

In the case of (INCF X), the job is to replace the value of the X
variable binding, because that is the storage place that the X
expression denotes. It means, essentially (SETF X (1+ X)). It does not
mean ``destructively increment the integer object pointed at by X'' it
means ``compute a new integer object, and change the binding of X to
that object''. Since X is a lexical variable, that rebinding is
confined to the lexical scope in which it occurs.

The call-by-name semantics of INCF means that to write your own
operators, you have to implement them as macros. An INCF-like
construct cannot be anything other than a macro:

  (defmacro ++ (place) `(incf ,place))

> Let's see
> 
> (defun ++second (x)
>   (incf (second x)))
> 
> (let ((loc '(0 1)))
>   (++second loc)
>   (second loc))

Here you are no longer modifying the local variable X, but a
substructure of the object that was passed in. So indeed, the
reference semantics of list passing makes itself apparent.

Incidentally, that object is a list literal generated by the QUOTE
operator. Therefore the behavior is undefined.

Lisp does indeed make the reference semantics of lists visible to the
programmer, who has the choice of exploiting it. However, Lisp has no
such semantics for integer objects.

There are no portable functions which will change an integer, such
that all existing references to that same integer will see the change.

Typically, small integers are represented directly as cells. Beyond a
certain range, the Lisp implementation switches from FIXNUM to BIGNUM
representation. Because integers are not destructively manipulated,
this change is practically invisible to the programmer, except as far
as performance and garbage generation are concerned, and the range at
which it occurs is very implementation-specific. There don't exist any
portable, standard operators that will touch up the bits of a BIGNUM
type value, so you can't demonstrate the reference semantics that way.
If you can't change an object, then reference semantics looks exactly
like value semantics---it's just a memory-copy-saving optimization of
value semantics, essentially.
From: Joe Marshall
Subject: Re: totally baffled
Date: 
Message-ID: <65kuyf2c.fsf@ccs.neu.edu>
········@ziplip.com" <·······@ziplip.com> writes:

> (defun ++ (x) 
>   (incf x))
>
> I was 110% sure that
>
> (let ((loc 1))
>   (++ loc)
>   loc)
>
> would return 2, but it returned 1. Using INCF instead of ++
> returns 2. Doesn't Lisp pass by reference?

No.  Lisp passes by value.