From: Neo-LISPer
Subject: universal SETF
Date: 
Message-ID: <87mzyh4h35.fsf@yahoo.com>
How come Lisp does not have a sort of "universal SETF" that would work
without requiring any extra definitions, similarly to assignment in C?
Can it be defined as a macro?

From: Kaz Kylheku
Subject: Re: universal SETF
Date: 
Message-ID: <cf333042.0410201127.7513ef54@posting.google.com>
Neo-LISPer <··········@yahoo.com> wrote in message news:<··············@yahoo.com>...
> How come Lisp does not have a sort of "universal SETF" that would work
> without requiring any extra definitions, similarly to assignment in C?

In C, the target of an assignment must be an expression that is a
(modifiable) lvalue. The repertoire of lvalues is hard-coded into the
language and cannot be extended by the programmer.

In Lisp, the target of an assignment operation like SETF, INCF and
others, must be a place.  There is a standard set of expressions that
can serve as places. Moreover, the programmer can define additional
places.

The Lisp SETF mechanism is arbitrarily extensible by the user, via
Lisp code that is just added to his program. Any conforming Lisp
implementation will understand that program and accept the extensions
to SETF.

The C programmer can only extend assignment by modifying the source
code of his C compiler. The programs which rely on the modifications
will only be understood by that modified compiler, and not by other C
compilers.

So, tell me again, which language has the universal assignment
operation?

And by the way, C++ overloadable assignment is not equivalent to what
Lisp has, because it does not work at the syntactic level. It does not
let you extend what is or is not an assignable lvalue. The left hand
side of a C++ user-defined operator must be a reference to a class
object. The operator is just a function.

A user-defined place in Lisp actually teaches SETF (and related
macros) how to understand new syntactic forms to treat them as places.
From: M Jared Finder
Subject: Re: universal SETF
Date: 
Message-ID: <2to5uaF21t32rU1@uni-berlin.de>
Kaz Kylheku wrote:
> Neo-LISPer <··········@yahoo.com> wrote in message news:<··············@yahoo.com>...
> 
>>How come Lisp does not have a sort of "universal SETF" that would work
>>without requiring any extra definitions, similarly to assignment in C?
> 
> 
> In C, the target of an assignment must be an expression that is a
> (modifiable) lvalue. The repertoire of lvalues is hard-coded into the
> language and cannot be extended by the programmer.
> 
> In Lisp, the target of an assignment operation like SETF, INCF and
> others, must be a place.  There is a standard set of expressions that
> can serve as places. Moreover, the programmer can define additional
> places.
> 
> The Lisp SETF mechanism is arbitrarily extensible by the user, via
> Lisp code that is just added to his program. Any conforming Lisp
> implementation will understand that program and accept the extensions
> to SETF.
> 
> The C programmer can only extend assignment by modifying the source
> code of his C compiler. The programs which rely on the modifications
> will only be understood by that modified compiler, and not by other C
> compilers.
> 
> So, tell me again, which language has the universal assignment
> operation?
> 
> And by the way, C++ overloadable assignment is not equivalent to what
> Lisp has, because it does not work at the syntactic level. It does not
> let you extend what is or is not an assignable lvalue. The left hand
> side of a C++ user-defined operator must be a reference to a class
> object. The operator is just a function.
 >
> A user-defined place in Lisp actually teaches SETF (and related
> macros) how to understand new syntactic forms to treat them as places.

That's not entirely true.  You can get a similar effect to Lisp's 
generalized variables (and C#'s properties) by defining a class that 
overloads conversion for reading and assignment for writing.  It's an 
ugly hack, but it does work:

class FakeInt {
public:
   operator int () {
     // put "get" code here
   }

   const int& operator=( const int& t ) {
     // put "set" code here
     return t;
   }
};

If I was to put this in a library, I'd probably want to take a 
generalized function pointer for both set and get, leading to ugly code 
like:

int getTimeOfDay();
void setTimeOfDay( int );
FakeInt timeOfDay() {
   return FakeInt( getTimeOfDay, setTimeOfDay );
}

I find the Lisp way of defining the functions TIME-OF-DAY and (SETF 
TIME-OF-DAY) to be much cleaner.  And that's what appeals to me the most 
about Lisp -- you can extend the language in a *clean* (and therefore 
easier to use/understand/debug) way.

   -- MJF
From: Frank Buss
Subject: Re: universal SETF
Date: 
Message-ID: <cl5rv6$pa0$1@newsreader2.netcologne.de>
Neo-LISPer <··········@yahoo.com> wrote:

> How come Lisp does not have a sort of "universal SETF" that would work
> without requiring any extra definitions, similarly to assignment in C?
> Can it be defined as a macro?

what do you mean with "extra definitions"? You can write (setf foo 42) to 
change the value of "foo", where is the extra definition?

-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Neo-LISPer
Subject: Re: universal SETF
Date: 
Message-ID: <87hdop4gin.fsf@yahoo.com>
Frank Buss <··@frank-buss.de> writes:

> what do you mean with "extra definitions"? 

DEFINE-SETF-EXPANDER
From: Rahul Jain
Subject: Re: universal SETF
Date: 
Message-ID: <87d5zclo81.fsf@nyct.net>
Ingvar <······@hexapodia.net> writes:

> Neo-LISPer <··········@yahoo.com> writes:
>
>> Frank Buss <··@frank-buss.de> writes:
>> 
>> > what do you mean with "extra definitions"? 
>> 
>> DEFINE-SETF-EXPANDER
>
> That is because = in C isn't (really) even going to be guaranteed to
> do The Right Thing (it often does, for simple data structures).
>
> You can make it so in C++ (In understand), but that requires defining
> a method named operator= in a class and can, as I understand it, only
> be done for classes taht's implemented sufficiently locally that
> there's source around.

Will that even allow for stuff like the ++ operator to be optimized for
a hash table by remembering which hash entry the value was found at? Or
does C++'s operator= not even manage to get that far?

In lisp we write

(setf (gethash key hashtable) 15)

Is

hashtable.get(key) = 15;

even legal C++?

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Kalle Olavi Niemitalo
Subject: Re: universal SETF
Date: 
Message-ID: <87d5zc8sfl.fsf@Astalo.kon.iki.fi>
Rahul Jain <·····@nyct.net> writes:

> Is
>
> hashtable.get(key) = 15;
>
> even legal C++?

It can be.  The easiest way to implement that is to make the
"get" function return a reference.  Then, even the read-only
looking operation "int x = hashtable.get(key);" must add the key
to the hash table if it isn't there already, so that the "get"
function can return a reference to the value cell of the entry.

It would be more in the style of C++ to name the function
"operator []" rather than "get", so that it can be used like
"hashtable[key] = 15;".  The "std::map" template does this.

Another way is to make "operator []" return a proxy object,
rather than a plain reference.  The proxy can then detect
whether its value being read or written, and handle both
cases separately.  This approach makes it possible to store
the elements of the container in an encoded or compressed form.
The "std::vector<bool>" type does this.
From: Frank Buss
Subject: Re: universal SETF
Date: 
Message-ID: <cl5s60$pa0$2@newsreader2.netcologne.de>
Frank Buss <··@frank-buss.de> wrote:

> what do you mean with "extra definitions"? You can write (setf foo 42)
> to change the value of "foo", where is the extra definition?

...and you can declare new local variables with let:

(let ((foo 42)) (princ foo))

like "int foo = 42" in C.

-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Peter Seibel
Subject: Re: universal SETF
Date: 
Message-ID: <m3ekjtv2wx.fsf@javamonkey.com>
Neo-LISPer <··········@yahoo.com> writes:

> How come Lisp does not have a sort of "universal SETF" that would work
> without requiring any extra definitions, similarly to assignment in C?
> Can it be defined as a macro?

What are you thinking of that you can do in C that you can't do in
Lisp with SETF? As far as I can tell the ability to extend SETF only
allows it go *beyond* the kinds of assignment that C supports. 

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Dirk Gerrits
Subject: Re: universal SETF
Date: 
Message-ID: <87lle1uzog.fsf@dirkgerrits.com>
Neo-LISPer <··········@yahoo.com> writes:

> How come Lisp does not have a sort of "universal SETF" that would work
> without requiring any extra definitions, similarly to assignment in C?
> Can it be defined as a macro?

I'm not sure what you're getting at.  Can you even do stuff like

  car(mylist) = 42;

in C?  (With 'car' as a function, not a preprocessor macro.)  I know
that you can do that (to some extent) in C++, but that's because C++ has
'references':

  int& car(IntList& list) { ... }

Actually, you could do pretty much the same thing in some older Lisps.
They had 'locatives', which are pretty similar to C++ references, but
more first class.  It's not that hard to create your own locatives of
sorts for Common Lisp, but I'm not entirely sure how much that would
accomplish over what we already have...  Anyone?

Kind regards,

Dirk Gerrits
From: Neo-LISPer
Subject: Re: universal SETF
Date: 
Message-ID: <87zn2gewz0.fsf@yahoo.com>
Dirk Gerrits <····@dirkgerrits.com> writes:

>  I know that you can do that (to some extent) in C++, but that's
>  because C++ has 'references':

Right. I meant "C++ without classes" :-)
 
> Actually, you could do pretty much the same thing in some older Lisps.
> They had 'locatives', which are pretty similar to C++ references, but
> more first class.  

Does anyone know why they didn't make it into CL? I feel like
references would be very useful, Michael Parker thought they were
handy enough to write a rather large package emulating some of their
functionality. Not including features does not sound like the Common
Lisp that I know.
From: Rahul Jain
Subject: Re: universal SETF
Date: 
Message-ID: <878ya0lo2g.fsf@nyct.net>
Neo-LISPer <··········@yahoo.com> writes:

> Does anyone know why they didn't make it into CL? I feel like
> references would be very useful, Michael Parker thought they were
> handy enough to write a rather large package emulating some of their
> functionality. Not including features does not sound like the Common
> Lisp that I know.

GET-SETF-EXPANSION is basically all there is to locatives. Just make two
closures sharing the "place" bindings with the code of the getter and
setter forms and you're set.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Lars Brinkhoff
Subject: Re: universal SETF
Date: 
Message-ID: <85y8i0a45z.fsf@junk.nocrew.org>
Rahul Jain <·····@nyct.net> writes:
> Neo-LISPer <··········@yahoo.com> writes:
> > Does anyone know why they didn't make it into CL? I feel like
> > references would be very useful, Michael Parker thought they were
> > handy enough to write a rather large package emulating some of their
> > functionality. Not including features does not sound like the Common
> > Lisp that I know.
> GET-SETF-EXPANSION is basically all there is to locatives. Just make two
> closures sharing the "place" bindings with the code of the getter and
> setter forms and you're set.

This recent thread may be relevant:
http://groups.google.com/groups?threadm=86d60fbawf.fsf%40cawtech.freeserve.co.uk

-- 
Lars Brinkhoff,         Services for Unix, Linux, GCC, HTTP
Brinkhoff Consulting    http://www.brinkhoff.se/
From: Kaz Kylheku
Subject: Re: universal SETF
Date: 
Message-ID: <cf333042.0410210053.638123e6@posting.google.com>
Neo-LISPer <··········@yahoo.com> wrote in message news:<··············@yahoo.com>...
> Dirk Gerrits <····@dirkgerrits.com> writes:
> 
> >  I know that you can do that (to some extent) in C++, but that's
> >  because C++ has 'references':
> 
> Right. I meant "C++ without classes" :-)
>  
> > Actually, you could do pretty much the same thing in some older Lisps.
> > They had 'locatives', which are pretty similar to C++ references, but
> > more first class.  
> 
> Does anyone know why they didn't make it into CL? I feel like
> references would be very useful, Michael Parker thought they were
> handy enough to write a rather large package emulating some of their
> functionality. Not including features does not sound like the Common
> Lisp that I know.

You can also write a very small, braindead package that will give you
references. Maybe not efficient ones, but working ones:

(defpackage "REFS"
  (:use "CL")
  (:export "REF" "DEREF" "WITH-REFS"))

(in-package "REFS")

(defstruct ref
 (get-func)
 (set-func))

(defun deref (ref)
  (funcall (ref-get-func ref)))

(defun (setf deref) (val ref)
  (funcall (ref-set-func ref) val))

(defmacro ref (place-expression)
  `(make-ref
     :get-func (lambda () ,place-expression)
     :set-func (lambda (val) (setf ,place-expression val))))

(defmacro with-refs ((&rest ref-specs) &body forms)
    `(symbol-macrolet 
       ,(loop for (var ref) in ref-specs
	      collecting (list var `(deref ,ref)))
       ,@forms))


Demo:

(use-package "REFS")

(defvar *list* (list 1 2 3 4))

(defvar *third* (ref (third *list*))) ;; make ref to third element

(deref *third*)
--> 3             ;; fetch through deref

(setf (deref *third*) 33)
--> 33

*list*
--> (1 2 33 4)    ;; store through deref

;;; convenient macro so you don't
;;; have to write (DEREF ...) as much

(with-refs ((t *third*)) (setf t 333))
--> 333

*list*
--> (1 2 333 4)   

In this case, the reference actually captures the place expression
(third *list*) , which will dynamically resolve through the current
binding of the *list* variable. That is to say, a given (deref
*third*) invocation will operate on whatever *list* happens to be
bound to in that context, not necessarily the top-level binding set up
in the defvar. So *third* is not a true locative in the sense that it
does not get a grip on some particular memory cell.

Even if you capture a lexical variable within your ref, that variable
could be assigned, and the ref will follow that assignment rather than
stick with the original list.

 (let ((list (list 1 2 3 4)))
   (let ((ref (third list)))
     (setf list (list 10 20 30 40))
     ; ref now ``points'' to the 30, not the 3.
      ))

This can be viewed as a bug or feature.
From: Tim Bradshaw
Subject: Re: universal SETF
Date: 
Message-ID: <1098364340.092483.106150@f14g2000cwb.googlegroups.com>
Neo-LISPer wrote:
> Dirk Gerrits <····@dirkgerrits.com> writes:
>
> >  I know that you can do that (to some extent) in C++, but that's
> >  because C++ has 'references':
>
> Right. I meant "C++ without classes" :-)
>
> > Actually, you could do pretty much the same thing in some older
Lisps.
> > They had 'locatives', which are pretty similar to C++ references,
but
> > more first class.
>
> Does anyone know why they didn't make it into CL? I feel like
> references would be very useful, Michael Parker thought they were
> handy enough to write a rather large package emulating some of their
> functionality. Not including features does not sound like the Common
> Lisp that I know.
From: Tim Bradshaw
Subject: Re: universal SETF
Date: 
Message-ID: <1098364361.941275.34610@c13g2000cwb.googlegroups.com>
Neo-LISPer wrote:
> Does anyone know why they didn't make it into CL? I feel like
> references would be very useful, Michael Parker thought they were
> handy enough to write a rather large package emulating some of their
> functionality. Not including features does not sound like the Common
> Lisp that I know.

Efficiency, I think: you want locatives to not nvolve consing, but it's
very
yard to do that without hardware support (which the LispMs had, of
course).

--tim
From: Szymon
Subject: Re: universal SETF
Date: 
Message-ID: <877jpljmx7.fsf@eva.rplacd.net>
Dirk Gerrits <····@dirkgerrits.com> writes:

> [.....]
> Actually, you could do pretty much the same thing in some older Lisps.
> They had 'locatives', which are pretty similar to C++ references, but
> more first class.  It's not that hard to create your own locatives of
> sorts for Common Lisp, but I'm not entirely sure how much that would
> accomplish over what we already have...  Anyone?

I found Michael Parker's stuff:

[ http://www.geocities.com/mparker762/cl-utils.html ].

From that page:

'... ref is library implementing generalized accessors for indexing into
arrays, bits, lists, strings, hashtables without really caring what it
is. It is extensible for user-defined collections as well. There is a
skeleton of the rest of a generalized container system, but it needs to be
fleshed out.

Also included is a portable locative facility, built on the generalized
accessor framework. It's not quite a replacement for the lispm locative
feature, but serves some of similar purposes.

Suggestions, criticism, and additional contributions welcome. ...'

Regards, Szymon.
From: Pascal Bourguignon
Subject: Re: universal SETF
Date: 
Message-ID: <87d5zd1lta.fsf@thalassa.informatimago.com>
Neo-LISPer <··········@yahoo.com> writes:

> How come Lisp does not have a sort of "universal SETF" that would work
> without requiring any extra definitions, similarly to assignment in C?
> Can it be defined as a macro?

How come C does not have a sort of "universal SETF" that would work
without requiring any extra definitions, similarly to SETF in Lisp?
Could it be defined in my dreams as a macro?

Look, I cannot even do that:

    typedef struct {
        int a;
        int b;
    } record_t;
#define dim (10)
    typedef record_t* table_t[dim,dim];

    int get_a(table_t table,int i,int j){
        if((0<=i)&&(i<dim)&&(0<=j)&&(j<dim)){
            return(table[i,j]->a);
        }else{
            exit(1);
        }
    }

    void main(void){
        table_t table;
        get_a(&table,0,0)=5550690;
    }

in C, while I can merely write it as:

    (defstruct record a b)
    (defmacro get-a (table i j)  `(record-a (aref ,table ,i ,j)))
    (defconstant +dim+ 10)
    (let ((table (make-array (list +dim+ +dim+))))
        (setf (get-a table 0 0) 5550690))

in Lisp.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

Voting Democrat or Republican is like choosing a cabin in the Titanic.
From: Lukas Mai
Subject: Re: universal SETF
Date: 
Message-ID: <cl6hsr$148$1@wsc10.lrz-muenchen.de>
Pascal Bourguignon schrob:
[...]
> Look, I cannot even do that:

>     typedef struct {
>         int a;
>         int b;
>     } record_t;
> #define dim (10)
              ^  ^?

>     typedef record_t* table_t[dim,dim];
                      |        ^ I think you want [dim][dim] here
                      ^ a 2d-array of pointers? that looks suspicious

>     int get_a(table_t table,int i,int j){
>         if((0<=i)&&(i<dim)&&(0<=j)&&(j<dim)){
>             return(table[i,j]->a);
              return table[i][j]->a;

>         }else{
>             exit(1);
                   ^ non-portable exit status
              exit(EXIT_FAILURE);
>         }
>     }

>     void main(void){
      ^ invalid return type for main()
      int main(void) {

>         table_t table;
>         get_a(&table,0,0)=5550690;
                |           ^ unportable int constant
                |             (int may be a 16 bit type)
                ^ get_a() expects a table_t, not a table_t *
          table is used without an initialization

          return 0; /* required in C89 */
>     }

> in C, while I can merely write it as:

>     (defstruct record a b)
>     (defmacro get-a (table i j)  `(record-a (aref ,table ,i ,j)))
>     (defconstant +dim+ 10)
>     (let ((table (make-array (list +dim+ +dim+))))
>         (setf (get-a table 0 0) 5550690))

> in Lisp.

I'd write it like this in C:
#include <stdlib.h>

typedef struct {
    long a;
    long b;
} record_t;

enum {DIM = 10};

long *get_a(record_t (*table)[DIM], size_t i, size_t j) {
    if (i >= DIM || j >= DIM) {
        exit(EXIT_FAILURE);
    }
    return &table[i][j].a;
}

int main(void) {
    record_t table[DIM][DIM];
    *get_a(table, 0, 0) = 5550690L;
    return 0;
}

SCNR, Lukas
-- 
use   warnings;                                    use      strict;
sub hacker'Perl        {     "Perl @_,"}           sub another'Just
                       {print"Just @_ "}
Just another Perl hacker, 
From: Marcin 'Qrczak' Kowalczyk
Subject: Re: universal SETF
Date: 
Message-ID: <87zn2h2xsc.fsf@qrnik.zagroda>
Neo-LISPer <··········@yahoo.com> writes:

> How come Lisp does not have a sort of "universal SETF" that would work
> without requiring any extra definitions, similarly to assignment in C?

Assignment in C is not universal either:

value gethash(value key, hash_table *table);

void test(hash_table *t, value k, value v) {
   gethash(k, t) = v;   /* Does not work. */
}

It does not work without extra definitions in Lisp for the same reason
as in C.

-- 
   __("<         Marcin Kowalczyk
   \__/       ······@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/