From: Peter Berck
Subject: structures
Date: 
Message-ID: <1991Apr09.091234.18122@kub.nl>
How can I 'choose slots' in a structure I have defined? Say I have the
structure (user) with the slots (name) and (adres), and I want
a function which accesses one of the two, supplied as an argument
to the function. (I hope I am making myself clear.)
For example:

(defun prt (someone slot)
    (print (user-slot someone)))

I would like to supply 'name' or 'adres' as argument (slot) to the function.
How do I do this? I could probably set things up differently, but I
would like to do it this way :)

thanks,
-peter

--------------------------------------
······@kub.nl     -     kubvx1::berckp

From: Barry Margolin
Subject: Re: structures
Date: 
Message-ID: <1991Apr9.202146.18803@Think.COM>
In article <······················@kub.nl> ······@kub.nl writes:
>How can I 'choose slots' in a structure I have defined? Say I have the
>structure (user) with the slots (name) and (adres), and I want
>a function which accesses one of the two, supplied as an argument
>to the function. (I hope I am making myself clear.)
>For example:
>
>(defun prt (someone slot)
>    (print (user-slot someone)))
>
>I would like to supply 'name' or 'adres' as argument (slot) to the function.
>How do I do this? I could probably set things up differently, but I
>would like to do it this way :)

If we had a FAQ list, this would certainly be on it (hmm, I could probably
save myself lots of time by compiling a FAQ list, so maybe I will).

There's currently no portable way to do this automatically.  Eventually it
will be doable using the CLOS metaobject protocol, though.

Right now, the only thing you can do is write a function that manually
selects between the slots, e.g.:

(defun prt (someone slot)
  (print (ecase slot
    	   (name (user-name someone))
    	   (adres (user-adres someone))))

You can also abstract this out so that you don't have to repeat it in
different functions:

(defun user-accessor (slot)
  (ecase slot
    (name #'user-name)
    (adres #'user-adres)))

(defun user-setter (slot)
  (ecase slot
    (name #'(lambda (user new-value)
	      (setf (user-name user) new-value)))
    (adres #'(lambda (user new-value)
	       (setf (user-adres user) new-value)))))

You can then write

(defun prt (someone slot)
  (print (funcall (user-accessor slot) someone)))

and

(defun set-someone (someone slot value)
  (funcall (user-setter slot) someone value))
--
Barry Margolin, Thinking Machines Corp.

······@think.com
{uunet,harvard}!think!barmar
From: Jeff Dalton
Subject: Re: structures
Date: 
Message-ID: <4535@skye.ed.ac.uk>
In article <·····················@Think.COM> ······@think.com (Barry Margolin) writes:
>In article <······················@kub.nl> ······@kub.nl writes:
>>How can I 'choose slots' in a structure I have defined? Say I have the
>>structure (user) with the slots (name) and (adres), and I want
>>a function which accesses one of the two, supplied as an argument
>>to the function. (I hope I am making myself clear.)
>>For example:
>>
>>(defun prt (someone slot)
>>    (print (user-slot someone)))
>>
>>I would like to supply 'name' or 'adres' as argument (slot) to the function.
>>How do I do this? I could probably set things up differently, but I
>>would like to do it this way :)

>There's currently no portable way to do this automatically.  Eventually it
>will be doable using the CLOS metaobject protocol, though.
>
>Right now, the only thing you can do is write a function that manually
>selects between the slots, e.g.:
>
>(defun prt (someone slot)
>  (print (ecase slot
>    	   (name (user-name someone))
>    	   (adres (user-adres someone))))
>
>You can also abstract this out so that you don't have to repeat it in
>different functions:
>
>(defun user-accessor (slot)
>  (ecase slot
>    (name #'user-name)
>    (adres #'user-adres)))

Etc.

An variation of this approach I've sometimes used is to define my own
structure-defining macro that expands into a DEFSTRUCT plus some code
that records the name of the access function that goes with each slot.
A simple version is defined below.  It doesn't support any of the 
DEFSTRUCT options :INCLUDE, :CONC-NAME, etc.  The mapping from names
of slots to names of accessor functions is stored in the SLOT-MAP
property of the structure name.

(defmacro define-structure (struct-name &rest slots)
  (let* ((slot-names
           (mapcar #'(lambda (s) (if (symbolp s) s (car s)))
                   slots))
         (accessors
           (mapcar #'(lambda (s) (concat-symbol struct-name "-" s))
                   slot-names)))
    `(progn
       (defstruct ,struct-name ,@slots)
       (setf (get ',struct-name 'slot-map)
             ',(mapcar #'list slot-names accessors))
       ',struct-name)))

(defun concat-symbol (&rest parts)
  (intern (apply #'concatenate 'string (mapcar #'string parts))))

Now we can define (GET-SLOT struct slot-name) -> value to return
the value of a slot given its name.  GET-SLOT relies on TYPE-OF
to return the type of a structure.  Although one is discouraged
from using TYPE-OF in programs, it is defined to work as required
for this case.

(defun get-slot (struct slot-name)
  (let ((entry (assoc slot-name (get (type-of struct) 'slot-map))))
    (if entry
        (funcall (second entry) struct)
      (error "Unknown slot ~S for struct ~S." slot-name struct))))

Your PRT function would then be

(defun prt (someone slot)
  (print (get-slot someone slot)))

-- Jeff
From: John McCarthy
Subject: Re: structures
Date: 
Message-ID: <JMC.91Apr23063454@DEC-Lite.Stanford.EDU>
The fact that using slot names as functional arguments requires
special hacks in Lisp is a consequence of the Lisp definers
of objects blindly following the mistakes of Pascal, etc.
CAR and CDR are slot names essentially, and from the very
beginning they were treated as function names.
From: Harley Davis
Subject: Re: structures
Date: 
Message-ID: <DAVIS.91Apr24144328@barbes.ilog.fr>
In article <·················@DEC-Lite.Stanford.EDU> ···@DEC-Lite.Stanford.EDU (John McCarthy) writes:

   The fact that using slot names as functional arguments requires
   special hacks in Lisp is a consequence of the Lisp definers
   of objects blindly following the mistakes of Pascal, etc.
   CAR and CDR are slot names essentially, and from the very
   beginning they were treated as function names.

There are certain advantages in specifying everything as functions -
uniformity of access and ease of implementation change, for example.
What I think is needed is a mapping from a datatype to the operations
supported by it.  For example, (operations pair) ==> (#'car #'cdr).
Attaching symbolic names to these operations and providing the mapping
from datatypes to these names and from the names to the actual
operations is another interesting level.

Also, "Lisp" is a little vague.  For example, in EuLisp or Le-Lisp
version 16, using symbolic slot names for either structures or classes
is completely supported by the language.  That this needs hacks in
CommonLisp should not be generalized to "Lisp".

-- Harley Davis
--
------------------------------------------------------------------------------
nom: Harley Davis			ILOG S.A.
net: ·····@ilog.fr			2 Avenue Gallie'ni, BP 85
tel: (33 1) 46 63 66 66			94253 Gentilly Cedex, France
From: Edward Wang
Subject: Re: structures
Date: 
Message-ID: <41872@ucbvax.BERKELEY.EDU>
>
In article <·················@DEC-Lite.Stanford.EDU> ···@DEC-Lite.Stanford.EDU (John McCarthy) writes:
>
>   The fact that using slot names as functional arguments requires
>   special hacks in Lisp is a consequence of the Lisp definers
>   of objects blindly following the mistakes of Pascal, etc.
>   CAR and CDR are slot names essentially, and from the very
>   beginning they were treated as function names.

I don't think this is quite true.  Adding the structure name
to the slot names to make slot function names is a feature.
It allows short slot names and longer, unambiguous slot function names.
In any case, Common Lisp lets you overide this:

	(defstruct (piffle (:conc-name ||))
	  ...)

So what's the problem?