From: Onay Urfalioglu
Subject: understanding function parameters
Date: 
Message-ID: <42c7dd3b$0$22767$9b4e6d93@newsread2.arcor-online.net>
example:

[1]> (defun f (a)(push 1 a))
F
[2]> (setq l '(4 5))
(4 5)
[3]> (f l)
(1 4 5)
[4]> l
(4 5)
-> here, it seems that parameter is given per 'value'.

now check out this one:

[24]> (defun f2 (a)(push 1 (first a)))
F
[25]> (setq ll '((1 2)(3 4)))
((1 2) (3 4))
[26]> (f2 ll)
(1 1 2)
[27]> ll
((1 1 2) (3 4))
-> here, parameter seems to be given by reference.
whats behind this? why is the first function "f" NOT modifying its
parameter, where the second function "f2" does??

thx
-- 
(+::+) oni (+::+)
(I already try to be as amusing as possible, my master!)

From: Joe Marshall
Subject: Re: understanding function parameters
Date: 
Message-ID: <acl4m2x1.fsf@comcast.net>
Onay Urfalioglu <·····@gmx.net> writes:

> example:
>
> [1]> (defun f (a)(push 1 a))
> F
> [2]> (setq l '(4 5))
> (4 5)
> [3]> (f l)
> (1 4 5)
> [4]> l
> (4 5)
> -> here, it seems that parameter is given per 'value'.

The parameter is passed by value, but...

> now check out this one:
>
> [24]> (defun f2 (a)(push 1 (first a)))
> F
> [25]> (setq ll '((1 2)(3 4)))
> ((1 2) (3 4))
> [26]> (f2 ll)
> (1 1 2)
> [27]> ll
> ((1 1 2) (3 4))
> -> here, parameter seems to be given by reference.

Cons cells are aggregate values, and are not copied when passed.

> whats behind this? why is the first function "f" NOT modifying its
> parameter, where the second function "f2" does??

Well, F *does* modify its parameter (the variable A in F is modified),
but that has nothing to do with the variable L outside of F.

But while F modifies changes what A refers to, F does not modify the
value that is originally bound to A.

F2 is a different story.  F2 does not modify its parameter (A
continues to be bound to the same cons cell throughout the call to F2).

F2, however, modifies the *contents* of that cons cell.  This is the
exact same cons cell in the CAR position in LL.  When F2 modifies it,
the modifications are `visible' everywhere.

I hope this helps.  If not, you will be sure to get a dozen more
replies.


-- 
~jrm
From: Tayssir John Gabbour
Subject: Re: understanding function parameters
Date: 
Message-ID: <1120402758.712105.184940@g14g2000cwa.googlegroups.com>
Joe Marshall wrote:
> Onay Urfalioglu <·····@gmx.net> writes:
>
> > example:
> >
> > [1]> (defun f (a)(push 1 a))
> > F
> > [2]> (setq l '(4 5))
> > (4 5)
> > [3]> (f l)
> > (1 4 5)
> > [4]> l
> > (4 5)
> > -> here, it seems that parameter is given per 'value'.
>
> The parameter is passed by value, but...
>
> > now check out this one:
> >
> > [24]> (defun f2 (a)(push 1 (first a)))
> > F
> > [25]> (setq ll '((1 2)(3 4)))
> > ((1 2) (3 4))
> > [26]> (f2 ll)
> > (1 1 2)
> > [27]> ll
> > ((1 1 2) (3 4))
> > -> here, parameter seems to be given by reference.
>
> Cons cells are aggregate values, and are not copied when passed.
>
> > whats behind this? why is the first function "f" NOT modifying its
> > parameter, where the second function "f2" does??
>
> Well, F *does* modify its parameter (the variable A in F is modified),
> but that has nothing to do with the variable L outside of F.
>
> But while F modifies changes what A refers to, F does not modify the
> value that is originally bound to A.
>
> F2 is a different story.  F2 does not modify its parameter (A
> continues to be bound to the same cons cell throughout the call to F2).
>
> F2, however, modifies the *contents* of that cons cell.  This is the
> exact same cons cell in the CAR position in LL.  When F2 modifies it,
> the modifications are `visible' everywhere.
>
> I hope this helps.  If not, you will be sure to get a dozen more
> replies.

If it doesn't, perhaps any last questions could be cleared up by
macroexpand-1'ing 
(push 1 a) and (push 1 (first a)).

Tayssir
From: Alan Crowe
Subject: Re: understanding function parameters
Date: 
Message-ID: <86r7eevknh.fsf@cawtech.freeserve.co.uk>
Onay Urfalioglu puzzled over:

     [1]> (defun f (a)(push 1 a))
     F
     [2]> (setq l '(4 5))
     (4 5)
     [3]> (f l)
     (1 4 5)
     [4]> l
     (4 5)
     -> here, it seems that parameter is given per 'value'.

What helped me is realising that let and lambda are
variations on a theme.

* (let ((l (list 4 5)))
    (let ((a l))
      (push 1 a))
    l)

(4 5)

seems obvious enough. So we expect the same result when we
rewrite it as

* (let ((l (list 4 5)))
    ((lambda (a)
       (push 1 a))
     l)
    l)

(4 5)

and the same result again when we give the function a name

* (defun f(a)(push 1 a))

F
* (let ((l (list 4 5)))
    (f l)
    l)

(4 5)

It gets really interesting when you want to write a function
to return a closure that you can use as a counter. The
obvious code

* (defun make-counter (initial-value)
    (let ((hidden-variable initial-value))
      (lambda () (incf hidden-variable))))

works:

* (defvar count (make-counter 99))
* (funcall count) => 100
* (funcall count) => 101

but is over-elaborate.
One may simple write:

* (defun make-counter (initial-value)
    (lambda () (incf initial-value)))
* (defvar accumulate (make-counter -1))
* (funcall accumulate) => 0
* (funcall accumulate) => 1

Implicit in defun is a lambda
(setf (symbol-function 'make-counter)
      (lambda(initial-value)
        (lambda () ...

and that outer lambda is creating a variable, called
initial-value. It is mutable, and of indefinite extent, so
is already suitable for closing over. There was no need to
create the additional variable that I called hidden-variable.

Although CL is multi-paradigm, the way that parameters are
passed, which you might describe as passing references by
value, does bias the language towards a functional style
such as

* (defvar l (list 4 5))
* (defun f (a) (cons 1 a))
* (setf l (f l)) => (1 4 5)
* l => (1 4 5)

Alan Crowe
Edinburgh
Scotland
From: Robert Maas, see http://tinyurl.com/uh3t
Subject: Re: understanding function parameters
Date: 
Message-ID: <REM-2005jul27-005@Yahoo.Com>
> From: Onay Urfalioglu <·····@gmx.net>
> example:
> [1]> (defun f (a)(push 1 a))
> F
> [2]> (setq l '(4 5))
> (4 5)
> [3]> (f l)
> (1 4 5)
> [4]> l
> (4 5)
> -> here, it seems that parameter is given per 'value'.

Yes, but make sure you understand that that 'value' being passed is in
fact a pointer to a daisy chain of standard pairs, i.e. a linked list.
Note that (push 1 a) means the same thing as (setq a (cons 1 a)), which
merely builds a new structure containing the original list as part of
it, and then assigns the local variable to that pointer to that new
bigger structure, and then returns the value of that local variable
i.e. the pointer to the new bigger structure. In your sequence of
toplevel R-E-P operations, you don't assign that new pointer to any
place, so it's basically discarded. (If you're using the standard CL
r-e-p loop which maintains values * ** and ***, then at the moment you
end that script it's still sitting in **, so you still have two more
chances to recover that value before it's gone forever.)

> now check out this one:
> [24]> (defun f2 (a)(push 1 (first a)))
> F

Note: That push code now is equivalent to
  (setf (car a) (cons 1 (car a)))
  i.e. (rplaca (car a) (cons 1 (car a)),
so even though you pass a *copy* of the value of the pointer to your
list, that line of code will follow the pointer to a real live standard
pair and really modify the CAR of it, except if you pass it a pointer
to something other than a standard pair in which case it'll bomb out
with some error/exception. There's no way this code can just make new
structure and never modify any already-existing structure.

> [25]> (setq ll '((1 2)(3 4)))
((1 2) (3 4))
[26]> (f2 ll)

Stop right there! You've passed a quoted constant, which is *not*
allowed to be modified internally, yet the function you called is going
to try to modify it anyway. You will get undefined behaviour, which
might be that it goes ahead and modifies it, but you get strange
unexpected and unwanted and improper side effects in other literal
constants that happen to share the same standard-pair you're trying to
modify, or it could bomb out with ATTEMPT-TO-MODIFY READ-ONLY-MEMORY
EXCEPTION, or it could notice you've asked it to modify read-only
memory and so it instead copies the data out to read-write memory and
makes the in-place modification there, which will cause other
unexpected and unanticipated strangness elsewhere in your program, etc.
You have no reason to expect anything reasonable.

(1 1 2)

At this point you know it violated the CL spec by either modifying a
constant, or by copying it when you asked it to do an in-place
modification.

[27]> ll
((1 1 2) (3 4))

At this point you know it really did violate the CL spec by
destructively modifying a read-only constant. Don't blame the
implementation. It's "undefined behaviour" in the spec. You violated
the spec and the implementation is free to do whatever it wants,
including delete all your files. (Maybe it did that, did you check?)

> -> here, parameter seems to be given by reference.

Nope, it seems to have ignored the fact that you gave it a constant,
and it went ahead and destructively modified the constant, very very
bad, but you asked for it.

> why is the first function "f" NOT modifying its
> parameter, where the second function "f2" does??

You're confused. The first function actually did modify the binding of
the local copy of the parameter you gave it. But because all parameters
are passed by value, that modification didn't propagate back to the
original value you passed to it, it propagated only back via the return
value, and only because you explicitly asked that to be returned, by
having that as the last (only) form in your function definition.

The second function didn't modify the binding of its local copy of your
parameter at all, but it *did* perform a structural modification inside
the object that parameter pointed at. Since you maintained a copy of
the pointer to that object, you were able to see that object in its
modified state after return from that function. Of you had done
this instead:
  [26]> (f2 '((1 2)(3 4)))
you wouldn't still have a pointer to that object you had passed as a
parameter, and you wouldn't be able to later see what modifications
had been performed on it inside the implementation of f2.

You need to learn the difference between modifying the binding of a
variable, whereby only code with access to that binding can see the
modification, compared to modifying the innerds of some object, whereby
anybody with access to that object can see the modification. Try this
for fun:
  (let ((x 5))
    (defun f1 () (incf x))
    (defun f2 () x))
then watch how whenever f1 is called the return value from subsequent
calls to f2 is affected, because f1 and f2 share a **BINDING**, so any
change f1 makes to that binding is seen by f2 also.

The lesson is that whenver two different parts of your code share
something, either (a pointer to) the same identical (EQ) object, or the
same binding, modifications on that object or binding can be seen
equally by all such code.