From: SRS
Subject: Pass by ref & generalized assignment
Date: 
Message-ID: <8ljmq0$8t2$1@nnrp1.deja.com>
As you probably know, C++ has a thing called 'pass by reference'. A
function that returns a reference can be used for its value, e.g. in
some expression, but can also be used as the left-hand-side of an
assignment operator, in which case the function acts as a sort of alias
for a variable.

In Lisp you have setf for generalized assignment, so that you can also
change the value of any 'place', even non-symbols. But for each kind of
new accessor function you define, you have to define a setf method for
it as well.

My (newbie) question is: Why doesn't Lisp have pass by reference as
well, so that i can automagically use any newly-defined accessor as the
place for setf? Is there a fundamental or practical reason why pass by
refence isn't done in Lisp?

- SRS


Sent via Deja.com http://www.deja.com/
Before you buy.

From: Philip Lijnzaad
Subject: Re: Pass by ref & generalized assignment
Date: 
Message-ID: <u7og3ma37z.fsf@o2-3.ebi.ac.uk>
SRS> My (newbie) question is: Why doesn't Lisp have pass by reference as
SRS> well, 

It doesn't need pass by reference if you have macros (such as setf)
and multiple-value returns.

SRS> so that i can automagically use any newly-defined accessor as the
SRS> place for setf? 

If I'm not mistaken, all standard accessors are automagically setf-able. The
ones that are not, are probably fairly non-trivial anyway, which would make it
as non-trivial to make them automagically setf-able. Hence, some human work
on this is required to make this work, using defsetf or defun. 

SRS> Is there a fundamental 

(yes, it's not needed)

SRS> or practical reason 

Yes, it's the functional programming (side-effect free) heritage of
Lisp. Side-effects are usually undesirable, so it's considered bad style to
e.g. assign things inside a call (which would have to be a macro call in
Lisp). Better return the new value, and make do the assignment explicitly
outside the function, e.g. using setf.

Frequently, the reason to use reference variables in imperative languages is
to be able to assign more than one value to more than one variable, as a
result of a function call.  The way to accomplish this in Lisp is by
returning using multiple values.  E.g., functions like FLOOR, TRUNCATE, ROUND
can all take a second argument (the divisor), and all return multiple values
QUOTIENT,REMAINDER. This can be thought of as returning a list of values, but
is more efficient. E.g., if you don't want REMAINDER, simply don't use it and
it will (or can) be optimized away by the compiler.

SRS> why pass by refence isn't done in Lisp?

Actually, at the risk of confusing you: all argument passing in lisp is by
reference. If a function gets passed in a list, then the function can do list
surgery on it, and the effects of it are visible when the function has
returned.

This is all pretty much like it is in Java, BTW. If you want to change the
object (i.e., not its state) passed in to a function, you typically pass in
an array of length one containing the object, then assign something to
array[0] inside the function (I don't think there appears to be
much need for your 'pass-by-reference' in Java either). Cheers,


                                                                      Philip
-- 
When C++ is your hammer, everything looks like a thumb. (Steven Haflich)
-----------------------------------------------------------------------------
Philip Lijnzaad, ········@ebi.ac.uk \ European Bioinformatics Institute,rm A2-24
+44 (0)1223 49 4639                 / Wellcome Trust Genome Campus, Hinxton
+44 (0)1223 49 4468 (fax)           \ Cambridgeshire CB10 1SD,  GREAT BRITAIN
PGP fingerprint: E1 03 BF 80 94 61 B6 FC  50 3D 1F 64 40 75 FB 53
From: Hannah Schroeter
Subject: Re: Pass by ref & generalized assignment
Date: 
Message-ID: <8ljvat$j1i$1@c3po.schlund.de>
Hello!

In article <··············@o2-3.ebi.ac.uk>,
Philip Lijnzaad  <········@ebi.ac.uk> wrote:

>[...]

>This is all pretty much like it is in Java, BTW. If you want to change the
>object (i.e., not its state) passed in to a function, you typically pass in
>an array of length one containing the object, then assign something to
>array[0] inside the function (I don't think there appears to be
>much need for your 'pass-by-reference' in Java either). Cheers,

Isn't it perhaps more efficient to use (cons obj nil) and use
(rplaca formal-parameter new-obj)?

Regards, Hannah.
From: Philip Lijnzaad
Subject: Re: Pass by ref & generalized assignment
Date: 
Message-ID: <u7ittu9ura.fsf@o2-3.ebi.ac.uk>
>> This is all pretty much like it is in Java, BTW. If you want to change the
>> object (i.e., not its state) passed in to a function, you typically pass in
>> an array of length one containing the object, then assign something to
>> array[0] inside the function (I don't think there appears to be
>> much need for your 'pass-by-reference' in Java either). Cheers,

Hannah> Isn't it perhaps more efficient to use (cons obj nil) and use
Hannah> (rplaca formal-parameter new-obj)?

What would be inefficient about simply returning new-obj ? 
(Possibly as part of a (values some-result new-obj yet-more-results). Even
worse: (cons obj nil) is really superfluous. 

Moreover, it looks very ugly, for the simple reason that this isn't Lisp.
Using this 'trick', you start violating the
objects-passed-in-can't-be-changed expectations of other readers/users of
your code. 

                                                                      Philip

-- 
When C++ is your hammer, everything looks like a thumb. (Steven Haflich)
-----------------------------------------------------------------------------
Philip Lijnzaad, ········@ebi.ac.uk \ European Bioinformatics Institute,rm A2-24
+44 (0)1223 49 4639                 / Wellcome Trust Genome Campus, Hinxton
+44 (0)1223 49 4468 (fax)           \ Cambridgeshire CB10 1SD,  GREAT BRITAIN
PGP fingerprint: E1 03 BF 80 94 61 B6 FC  50 3D 1F 64 40 75 FB 53
From: Erik Naggum
Subject: Re: Pass by ref & generalized assignment
Date: 
Message-ID: <3173538444289964@naggum.net>
* Philip Lijnzaad <········@ebi.ac.uk>
| Moreover, it looks very ugly, for the simple reason that this isn't Lisp.

  If you're new to (Common) Lisp, it helps your growing credibility to
  avoid such obvious "my mind isn't big enough for this!" complaints.

| Using this 'trick', you start violating the
| objects-passed-in-can't-be-changed expectations of other
| readers/users of your code.

  What kind of expectation is that?  Seems awfully unwarranted to me.
  It could almost be something left over from some Scheme course.

#:Erik
-- 
  If this is not what you expected, please alter your expectations.
From: Jason Trenouth
Subject: Re: Pass by ref & generalized assignment
Date: 
Message-ID: <gj3rnskpejmgoul42vg50pmqf8vi3bfq9l@4ax.com>
On 25 Jul 2000 11:55:44 +0100, Philip Lijnzaad <········@ebi.ac.uk> wrote:

> This is all pretty much like it is in Java, BTW. If you want to change the
> object (i.e., not its state) passed in to a function, you typically pass in
> an array of length one containing the object, then assign something to
> array[0] inside the function (I don't think there appears to be
> much need for your 'pass-by-reference' in Java either). Cheers,

Well, it would be better if Java had either multiple return values or reference
parameters. It would have simplified the Java-CORBA binding. Currently all IDL
types need to have Java Holder classes defined for them so that you return them
from operations with out or inout parameters.

__Jason
From: Philip Lijnzaad
Subject: Re: Pass by ref & generalized assignment
Date: 
Message-ID: <u7g0oy9ucr.fsf@o2-3.ebi.ac.uk>
Jason> On 25 Jul 2000 11:55:44 +0100, Philip Lijnzaad <········@ebi.ac.uk> wrote:
>> This is all pretty much like it is in Java, BTW. If you want to change the
>> object (i.e., not its state) passed in to a function, you typically pass in
>> an array of length one containing the object, then assign something to
>> array[0] inside the function (I don't think there appears to be
>> much need for your 'pass-by-reference' in Java either). Cheers,

Jason> Well, it would be better if Java had either multiple return values 

yes; I think the Python syntax: 

  a,b,c = some_multivalue_func(args);

would be reasonable (and possible).

Jason> or reference parameters.

less sure: the simple rule "can't replace the object in a function
call" is now less simple. 

Jason> It would have simplified the Java-CORBA
Jason> binding. Currently all IDL types need to have Java Holder classes
Jason> defined for them so that you return them from operations with out or
Jason> inout parameters.

yes, but it doesn't seem to me to be such a big deal, really. The only thing
that multiple-values doesn't really address is inout parameters: you'd have
to pass in the same parameter, which is then changed and returned (I believe
that this is what the CORBA Lisp mapping does). Some argue that this is
wrong, or at least not succinct. I'd argue that inout parameters aren't that
pretty anyway :-) 
                                                                      Philip
-- 
When C++ is your hammer, everything looks like a thumb. (Steven Haflich)
-----------------------------------------------------------------------------
Philip Lijnzaad, ········@ebi.ac.uk \ European Bioinformatics Institute,rm A2-24
+44 (0)1223 49 4639                 / Wellcome Trust Genome Campus, Hinxton
+44 (0)1223 49 4468 (fax)           \ Cambridgeshire CB10 1SD,  GREAT BRITAIN
PGP fingerprint: E1 03 BF 80 94 61 B6 FC  50 3D 1F 64 40 75 FB 53
From: Frank A. Adrian
Subject: Re: Pass by ref & generalized assignment
Date: 
Message-ID: <6jrf5.800$o01.336875@news.uswest.net>
"Philip Lijnzaad" <········@ebi.ac.uk> wrote in message
···················@o2-3.ebi.ac.uk...

> yes; I think the Python syntax:
>
>   a,b,c = some_multivalue_func(args);

Nope.  Remember that C already has a syntactic use for ","..  This construct
would clash too much with the use of "," as an expression separator.  Now,
using "`" as a separator.  Would make the code look real pretty!

    a`b`c = some_multivalue_func(args);
    int`double`bool a_function(...) {
        ...
        return 1`10.345`false;
    }

Plus by separating types by a type combination operator, one could do cool
stuff like this:

int`double`float`char a, *b`f,g,**h,i`r,s=5,t=3.1415`x='a';

or pass implicit structures into a function:

bool f(int`bool, char){ ... }

to be called as:

    b = f(1`false, 'a');

The use of a separate character makes the cartiaian type extension QUITE
beautiful and well in keeping with C's readable syntax!  And think of what
fun the C++'ers would have with this, too!  I bet it could even be added to
Java...

Not to mention the type combination fun one could have by using $ as a type
union operator and : as a bitfield tag with { and } acting as grouping
operators!  And don't forget the [ and ] for arrays!

extern long${short`int:16}${char[4]} my_function(int`char, bool`float);

Now there's a type declaration for you!

faa
From: Erik Naggum
Subject: Re: Pass by ref & generalized assignment
Date: 
Message-ID: <3173510161279560@naggum.net>
* SRS <·····@my-deja.com>
| My (newbie) question is: Why doesn't Lisp have pass by reference as
| well ...

  Because C++ doesn't have multiple return values.

#:Erik
-- 
  If this is not what you expected, please alter your expectations.
From: ·····@corman.net
Subject: Re: Pass by ref & generalized assignment
Date: 
Message-ID: <8lpqdl$ql8$1@nnrp1.deja.com>
In article <············@nnrp1.deja.com>,
  SRS <·····@my-deja.com> wrote:
> As you probably know, C++ has a thing called 'pass by reference'. A
> function that returns a reference can be used for its value, e.g. in
> some expression, but can also be used as the left-hand-side of an
> assignment operator, in which case the function acts as a sort of
alias
> for a variable.
Your characterization of C++ leaves out some important points. The
object being referenced must have an assignment operator implemented
for it; if it doesn't, you have to write it. This is pretty much the
same situation as in Common Lisp, it seems to me. Also, a function
in C++ cannot just create a new object and return it as a reference,
unless care is taken to allocate the reference for that object
somewhere besides the current function's stack frame. This usually
means a heap allocation of the reference itself, not just of the
object. Also, any manipulations of that reference now do double
indirections, and the lifetime of the reference must be handled
correctly. These are all costs and tradeoffs in the language design.

>
> My (newbie) question is: Why doesn't Lisp have pass by reference as
> well, so that i can automagically use any newly-defined accessor as
the
> place for setf?
There is built-in support for many reference types:
(car x) where x is a cons, is a reference. The invisible
dereferencing that C++ is missing, so you have to return
x from the function, and then assign to the reference (car x).
This is a pretty fundamental language design and philosophy difference,
it seems to me, and it is reasonable to say that C++ references
are complicated to understand and use correctly.

>Is there a fundamental or practical reason why pass by
> refence isn't done in Lisp?

I have been building lisp interpreters and compilers for many years.
When I first started to implement a Common Lisp system, I discovered
SETF. I had already programmed in C++ (and other languages with
references) and I got this "aha" lightbulb came on. I thought that
the fact that SETF existed must mean that actually all lisp objects
were passed around by reference, so that SETF could be simply
implemented by dereferencing the passed object. I modified the
interpreter I was working on to work this way. Boy was that a
mistake! Passing everything by reference caused abysmal performance,
all kinds of reference variables had to be allocated on the heap,
the garbage collector got much more complicated, etc. I gradually
learned how SETF is a logical construct, which simply caused some
setter function to be invoked. I changed everything back to pass by
value, and life was good again.

I think you were very right to ask this question to begin with, since
I struggled with it at one time. Now, you need to stop thinking why
doesn't lisp have this or that feature from this other language.
Rather, you should think about some extension to lisp that
addresses some real weakness of the language (that you perceive,
after working in lisp for some time)
and suggest such an extension be considered by others. Once you
have specified the extension, syntactically, and thought through
the issues, you will no doubt discover that it can be easily
implemented (probably with macros) in any existing lisp system.
Then you will have what you want, and everyone else will be free to
start using it as well.

Roger Corman


Sent via Deja.com http://www.deja.com/
Before you buy.
From: Drew McDermott
Subject: Re: Pass by ref & generalized assignment
Date: 
Message-ID: <3980B846.5F2296A8@yale.edu>
SRS wrote:

My (newbie) question is: Why doesn't Lisp have pass by reference as

> well, so that i can automagically use any newly-defined accessor as the
> place for setf? Is there a fundamental or practical reason why pass by
> refence isn't done in Lisp?

I'm surprised no one has pointed out that you can implement call by
reference in Lisp, if you don't mind a few extra parentheses (which, as a
Lisp hacker, you don't):

(in-package :user)

(defstruct (reference
             (:print-function
                (lambda (r srm depth)
                        (declare (ignore depth))
                   (format srm "#<Reference to ~s>"
                           (reference-name r)))))
   name accessor setter)

;;; (ref (car x)) makes a reference to x
(defmacro ref (x)
   (let ((newval (gensym)))
      `(make-reference
             :name ',x
             :accessor #'(lambda () ,x)
             :setter #'(lambda (,newval)
                          (setf ,x ,newval)))))

;;; (val r) gets the value
(defun val (ref)
   (funcall (reference-accessor ref)))

;;; (setf (val r) v) changes the value
(defun val-set (ref v)
   (funcall (reference-setter ref) v))

(defsetf val val-set)

;;; Reverse list l, putting the result in res (a reference to a
;;; list, which someone else has initialized).
(defun unlispish-reverse (l res)
   (do ((l1 l (cdr l1)))
       ((null l1))
      (setf (val res)
            (cons (car l1) (val res)))))

;;; Here's how we might call it:
(defun grotesque-hack (l)
   (let ((result '()))
      (unlispish-reverse l (ref result))
      result))

Here's what it looks like in acton:

 > (setq r (ref x))
#<Reference to X>

 >(setf x 'wow)
WOW

>(val r)
WOW

>(setf (val r) "foo")
"foo"

> (val r)
"foo"

> x
"foo"

> (grotesque-hack '(a b c))
(C B A)

Actually, this isn't quite call by reference, it's more like call by name.
It doesn't do the right thing with something like

   (ref (elt longlist (fact 100)))

You would have to do some setf-expander tricks to avoid recomputing the
factorial every time you accessed or set.

However, there's no point in fixing this, because I've never had any use
for it.  As others have pointed out, the situations where call by reference
is useful are covered by other mechanisms in Lisp.

    -- Drew McDermott