This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: setf.scm



mdj@nada.kth.se writes:
> This mechanism wasn't based on your code, but was, what was supposed
> to be, an improvement on the mechanism in STk which also is Common
> Lispish.
> 

I hardly take responsibility for the interface, it has been reinvented
many times. I was just referring to my code by way of contrast.

> > For instance, code like this:
> > 
> > (define (mutate-cons-cell accessor cell new-value)
> >   (setf! (accessor cell) new-value))
> > 
> > (define my-cell (cons 3 4))
> > (define my-cell (cons 3 4))
> > 
> > (mutate-cons-cell car my-cell 'x)
> > 
> > (mutate-cons-cell cdr my-cell 'y)
> > 
> > Will silently do the shockingly unexpected wrong thing and leave
> > my-cell with a value of (y . 4), whereas a fully Common Lisp-like setf
> > would have complained, and my code would have done the right thing. I
> > think the current code is thus the worst of all possible worlds,
> > semantics-wise. (I predicted this on reading the code, but testing
> > confirms).
> 
> I agree.  I think it should complain.
> 
> I made a thought error (Christian's code was OK, but I added the
> strange stuff) when implementing this.  I must have thought about
> dynamic properties one second and static in the other.  Sorry.  :(
> 
> > I also don't think it is useful to allow getters and setters to be
> > macros (and obviously that can't be done with the non-memoizing
> > version where setter is a procedure since code written to use that
> > with macros would be utterly uncompilable). Is there a particular
> > purpose that was envisioned for?
> 
> It was supposed to be an implementation of Common Lisp's generalized
> locations, where getters and setters can be special forms.
> 

Scheme does not have any standard getters or setters that are special
forms. I don't believe such a thing should happen either. Getters or
setters that are macros _may_ be useful but I don't think they are
more useful than dynamic behavior.


> On the other hand I don't see a strong need to have dynamic
> behaviour.  There is a reason why `set' wasn't included in RnRS.
> E.g., in your example above I think it would be more natural to write
> 
>   (mutate-cons-cell set-car! my-cell 'x)
> 
>     or
> 
>   (mutate-cons-cell (setter car) my-cell 'x)
> 
>     and
> 
>   (define (mutate-cons-cell setter cell new-value)
>     (setter cell new-value))
> 
> (I'm aware that you wrote the code above to demonstrate my bug, which
>  it excellently did, not to show a typical usage of dynamic setf!.)
> 
> In fact, the point of doing a thing like
> 
>   (set! (car x) 3)
> 
> is to get better syntax.  It's supposed to be "syntactic sugar".
> If you let the cadar be a variable, it seems to defeat the purpose to
> yield clearer code.
> 
> I'll change the implementation to a purely static one.


I think a purely dynamic one would be more in the spirit of Scheme. I
realize my example of dynamic use of setf! is not a truly useful
example, but I believe such examples exist. For instance, some
procedures may have anonymous setters. Suppose I defined `first'
through `tenth' as well as having `cadr' and `cdddr' and such things,
and all of these had setters associated, but none of those setters had
names. (set-tenth! and set-cdddr! would certainly be bloat, and not
having to have such things is part of the problem setf! is supposed to
solve). Now suppose I do

(define (swap-list-structure-locations! list-structure accessor1 accessor2) 
  (let ((value1 (accessor1 list-structure))
	(value2 (accessor2 list-structure)))
    (setf! (accessor2 list-structure)


Yes, I realize a generic swapf! macro would be a more general
solution, I am just suggesting that dynamically passing around
procedures is a much more common paradigm in Scheme than Common Lisp
and so people will attempt to apply that to setters and lose.

I also realized that the above code is somewhat broken, since if the
first setf! changes the list in such a way that the other accessor no
longer accesses the same location, the result will be totally wrong.

I was going to suggest that the complexity in Common Lisp's setf was
there to make swapf and psetf work right, but this is not the case
Common Lisp psetf is subject to the same bug as the above code.


Another case where dynamism would be useful: suppose I do

(define (make-point x y) (list x y))
(define point-x car)
(define point-y cadr)

It sure would be nice to have setters for point-x and point-y for
free.


It also seems to me that deriving the mutator from the accessor could
be useful in the context of records or object systems.


Yet another case where I think dynamic setf is useful (again a vague
prototypical example, not meant to be real code):

(define (make-toggling-cell initial-state value1 value2) 
  (cons initial-state (cons value1 value2)))

(define (toggling-cell-toggle! tcell)
  (set-car! tcell (not (car tcell))))

(define (toggling-cell-ref tcell)
  ((if (car tcell) car cdr) (cdr tcell)))

(define (toggling-cell-set! tcell value)
  (setf! ((if (car tcell) car cdr) (cdr tcell)) value))

Note the informative parallelism between the last two definitions.


And as a final note, Common Lisp does not allow macros to have setf
methods defined - it macroexpands the place form if the first position
of the form refers to a macro - and it appears to require setf-methods
to be functions as well, at least as I read the relevant section of
CLtL2 (http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node80.html). I
don't believe that adding this capability is a useful extension.


All in all, I think dynamic setf without macro getters or setters
would be much better.

 - Maciej