common lisp: slot-value for defstruct structures

2019-02-21 23:19发布

问题:

In common lisp, what can I use to access structure slot using slot name/symbol?

What I want is

(defstruct point (x 0) (y 0))    
(defmacro -> (struct slot) `(slot-value ,struct ,slot))

(setf p (make-point))
(setf (slot-value p 'x) 1)
(setf (-> p 'y) 2)

I'm using clozure cl, and In clozure cl this works. However, AFAIK this is non-standard behavior (equivalent to "undefined behavior" C++). I'm not planning to switch to another CL implementation, so should I keep using slot-value for structures, or is there a better way to do it?

回答1:

Usually you would use accessor functions with structures.

Your code defines the accessor functions point-x and point-y. You can use those.

You can also use SLOT-VALUE with structures on implementations which support it. I guess that's most implementations (GCL would be an exception). There is Lisp software which assumes that SLOT-VALUE works for structures. I don't think implementations will remove support for it. It'a not in the standard, because some implementors wouldn't want to provide this functionality in deployed applications.

So both ways are okay.

If you want to have short names, go with accessors:

CL-USER 109 > (defstruct (point :conc-name)
                (x 0) (y 0))
POINT

CL-USER 110 > (make-point :x 5 :y 3)
#S(POINT :X 5 :Y 3)

CL-USER 111 > (setf p1 *)
#S(POINT :X 5 :Y 3)

CL-USER 112 > (x p1)
5

CL-USER 113 > (setf p2 (make-point :x 2 :y 3))
#S(POINT :X 2 :Y 3)

CL-USER 114 > (list p1 p2)
(#S(POINT :X 5 :Y 3) #S(POINT :X 2 :Y 3))

CL-USER 115 > (mapcar 'x (list p1 p2))
(5 2)

Name clashes between various accessor functions then would have to be prevented by a package.

If you want to write a shorter version of SLOT-VALUE, that's also fine. Write a macro. Or write an inlined function. Sure - why not?

As I said, SLOT-VALUE works with structures in most implementations. In this case you should not care that the ANSI CL spec does not define that. In many ways implementations extend the ANSI CL spec. For example by SLOT-VALUE working on structures, implementing streams as CLOS classes, implementing conditions as CLOS classes, providing a Meta-object Protocol, ...