[comp.lang.lisp] updating random slots in

pc@flash.bellcore.com (01/13/90)

Given something like:

(defstruct test
	(one)
	(two)
	(three))

one can do something like

(setq access-function 'test-one)

(setq instance (make-test :one 1 :two 2 :three 3))

(funcall access-function instance) => 1

There appears to be no Common LISP way to similarly update a random
slot.  The best one can do seems to be:

(defun update-slot (object slot value)
  (case slot
    (one (setf (test-one object) value)
    ....
  ))

Must i explicitly define my structure as say a list, to be able to
replace an arbitrary component?  Symbolics documentation on LOCFs is a
little sketchy, but perhaps i can use them?

Ideas?


Peter Clitherow

barmar@think.com (Barry Margolin) (01/13/90)

In article <18837@bellcore.bellcore.com> pc@flash.bellcore.com writes:
>There appears to be no Common LISP way to similarly update a random
>slot.  The best one can do seems to be:

You can do

(setq updater-function #'(lambda (object value)
			   (setf (test-one object) value)))

(funcall updater-function instance value)

In ANSI Common Lisp you'll be able to use #'(setf test-one) to access the
updater function directly.
--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

pc@flash.bellcore.com (01/15/90)

> In article <18837@bellcore.bellcore.com> pc@flash.bellcore.com writes:
> >There appears to be no Common LISP way to similarly update a random
> >slot.  The best one can do seems to be:
> 
> You can do
> 
> (setq updater-function #'(lambda (object value)
> 			   (setf (test-one object) value)))
> 
> (funcall updater-function instance value)
> 

Yes, that's so.  But given a defstruct with 50 slots, i must define an
updator function for each, which seems wasteful, given that the DEFSTRUCT
has already defined one.

> In ANSI Common Lisp you'll be able to use #'(setf test-one) to access the
> updater function directly.


Ah, now this is closer to what i was looking for.  But what i want to
do, is define a SETFable function created with (INTERN (string-append
<defstruct-name> "-" <slot-name>)).  Perhaps i really have to throw the
whole expression i've consed up to EVAL.  But that really is a bit
gross.

Peter Clitherow

lou@atanasoff.rutgers.edu (Lou Steinberg) (01/16/90)

In article <18963@bellcore.bellcore.com> pc@flash.bellcore.com writes:

> > In article <18837@bellcore.bellcore.com> pc@flash.bellcore.com writes:
> 
> > In ANSI Common Lisp you'll be able to use #'(setf test-one) to access the
> > updater function directly.
> 
> Ah, now this is closer to what i was looking for.  But what i want to
> do, is define a SETFable function created with (INTERN (string-append
> <defstruct-name> "-" <slot-name>)).  Perhaps i really have to throw the
> whole expression i've consed up to EVAL.  But that really is a bit
> gross.

Well, you could set up your own hash table or other data structure to
convert the symbols returned by INTERN into the functions (using e.g.
#'(setf test-one) to find out what they are).  Better yet,
you could use some such data structure to directly map the pairs
(defstruct-name slot-name) into setf functions.  

Or, some simple poking around might well tell you how to access the
SETF functions already there in your implementation.  E.g. I think in
Allegro if you look at the property list of a symbol with a setf-able
function it is pretty clear how to find the setf function.  Of course,
this will not be portable, and may even break with a new release of
your lisp.
-- 
					Lou Steinberg

uucp:   {pretty much any major site}!rutgers!aramis.rutgers.edu!lou 
arpa:   lou@cs.rutgers.edu

eliot@phoenix.Princeton.EDU (Eliot Handelman) (01/16/90)

In article <Jan.15.12.33.43.1990.625@atanasoff.rutgers.edu> lou@atanasoff.rutgers.edu (Lou Steinberg) writes:
;In article <18963@bellcore.bellcore.com> pc@flash.bellcore.com writes:
;
;>                                                    But what i want to
;> do, is define a SETFable function created with (INTERN (string-append
;> <defstruct-name> "-" <slot-name>)).  Perhaps i really have to throw the
;> whole expression i've consed up to EVAL.  But that really is a bit
;> gross.

I ran into a similar problem, compounded by the fact that I wanted to
define a few extra options to defstruct, so I wound up writing a 
defstruct preprocessor. I save any values that interest me, such as the
names of all the accessors. 

Zetalisp had the defstruct-description structure to access basic information,
like the names of all the slots, the names of the accessors to each slot, etc.
Too bad CL dropped it. Why was that? Anything to do with metaobjects?

cowan@marob.masa.com (John Cowan) (01/17/90)

In article <18837@bellcore.bellcore.com> pc@flash.bellcore.com writes:

[defstruct deleted]

>There appears to be no Common LISP way to similarly update a random
>slot [of a structure].  The best one can do seems to be:

[example using 'case' deleted]

>Must i explicitly define my structure as say a list, to be able to
>replace an arbitrary component?  Symbolics documentation on LOCFs is a
>little sketchy, but perhaps i can use them?
>
>Ideas?

This is handled on page 96 of CLtL (1st ed.), which discusses setf.
That is section 7.2, (setf), seventh bullet, in case paginations differ.
It is legal to say (setf (apply #'fn args) newval).

In this case, one could say something like:
	(setf instance (make-fubar :one 'a :two 'b :three 'c))
	(setf accessor #'fubar-one)	; note use of #' here
	(setf (apply accessor (list instance)) newvalue)
to change the :one slot of instance to newvalue.

The book warns that this works only if the setf method for the function
is of a normal kind, i.e. produces an update function that resembles the
access function except for having a final argument added which is the new value.
So the solution is somewhat implementation dependent, but should work
on any "reasonable" implementation.  (I have not tested it past one
implementation.)

dlw@odi.com (Dan Weinreb) (01/17/90)

In article <12955@phoenix.Princeton.EDU> eliot@phoenix.Princeton.EDU (Eliot Handelman) writes:

   Zetalisp had the defstruct-description structure to access basic information,
   like the names of all the slots, the names of the accessors to each slot, etc.
   Too bad CL dropped it. Why was that? Anything to do with metaobjects?

In a lot of cases like this, the feature did not carry over into CL
because, while many people saw the motivation, they didn't all like
the details, and it didn't seem that the time or energy existed to
form a concensus.  Quite a few good Zetalisp features were left by the
wayside in this way.  Often we (Moon and I) told everybody that the
features were genuinely important, but the others didn't believe us,
thinking the features were too complicated and not very useful.  Now a
some of them are (apparently) being added as part of the ANSI
standardization process, as the user demand becomes clear.

jeff@aiai.ed.ac.uk (Jeff Dalton) (01/18/90)

In article <18963@bellcore.bellcore.com> pc@flash.bellcore.com writes:
>Yes, that's so.  But given a defstruct with 50 slots, i must define an
>updator function for each, which seems wasteful, given that the DEFSTRUCT
>has already defined one.

But the system may not have defined one.  Instead of having a setter
function for each slot of each defstruct type, it may just have one
setter function that's used for all slots and is called with an int
that gives the offset of the slot in the structure.  For example,

  > (defstruct struct a-slot)
  struct

  > (macroexpand-1 (setf (struct-a-slot x) 'z))
  (system:structure-set x 0 'z)

-- Jeff

jeff@aiai.ed.ac.uk (Jeff Dalton) (01/18/90)

In article <25B37814.3312@marob.masa.com> cowan@marob.masa.com (John Cowan) writes:
>In article <18837@bellcore.bellcore.com> pc@flash.bellcore.com writes:
>>Must i explicitly define my structure as say a list, to be able to
>>replace an arbitrary component?

>This is handled on page 96 of CLtL (1st ed.), which discusses setf.
>That is section 7.2, (setf), seventh bullet, in case paginations differ.
>It is legal to say (setf (apply #'fn args) newval).

>In this case, one could say something like:
>	(setf instance (make-fubar :one 'a :two 'b :three 'c))
>	(setf accessor #'fubar-one)	; note use of #' here
>	(setf (apply accessor (list instance)) newvalue)
>to change the :one slot of instance to newvalue.

What CLtL says is that SETF will work for a call to APPLY provided
that (1) APPLY's first argument has the form #'function-name and
(2) calls to function-name are recognized as places by SETF.

That is, to be able to do

   (setf (apply #'f ...apply-args...) y)

you have to be able to do

   (setf (f ...args...) y)

In your example above, ACCESSOR would not be recognized as a place
by SETF, nor do you write #'ACCESSOR.  So

   (setf (apply accessor ...) ...)

probably won't work.  On the other hand,

   (setf (apply #'fubar-one ...) ...)

looks like it ought to work.  Unfortunately it doesn't in any of the
Common Lisps I've tried.

>The book warns that this works only if the setf method for the function
>is of a normal kind, i.e. produces an update function that resembles the
>access function except for having a final argument added which is the new
>value.

That's probably it.  Presumably nothing says the SETF methods for
structure slot accessors have the required property.  Too bad if so.

>So the solution is somewhat implementation dependent, but should work
>on any "reasonable" implementation.  (I have not tested it past one
>implementation.)

Does (SETF (APPLY ACCESSOR ...) ...) really work somewhere?

-- Jeff

barmar@think.com (Barry Margolin) (01/18/90)

In article <25B37814.3312@marob.masa.com> cowan@marob.masa.com (John Cowan) writes:
>	(setf (apply accessor (list instance)) newvalue)

No, this isn't valid.  The first argument to APPLY when it is being used as
a SETF place must be a constant.  SETF is a macro, so it must know at
expansion time what the accessor is so that it can expand into a call to
the corresponding updater.

>(I have not tested it past one implementation.)

If it works, it's due to an implementation extension.  It doesn't work on
my Symbolics system or in Lucid CL; the latter gives the error "SETF of
APPLY is only defined for function args like #'symbol."
--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar