tags:

views:

104

answers:

2

In common lisp I've noticed that I can write this:

(defun foo (&key (a 1) (b 2) (c (+ a b))) (print (+ a b c)))

And when I call (foo), 6 is printed. So the argument c can refer to values set for a and b. But I can't seem to find a way to do something similar with defstruct. Something like:

CL-USER> (defstruct thing a b c)
THING
CL-USER> (setq q (make-thing :a 1 :b 2 :c (+ a b)))
; Evaluation aborted
CL-USER> (setq q (make-thing :a 1 :b 2 :c (+ :a :b)))
; Evaluation aborted

Is there a way to do this?

+3  A: 

Not that way. But using Lisp reader tricks you can do:

(make-thing :a #1=1 :b #2=2 :c (+ #1# #2#))

Otherwise use defclass and specialize the generic function shared-initialize.

Note that these reader macros will reference the form, not the result of evaluating it. Thus

(make-thing :id #1=(generate-unique-id) :my-id-is #1#)

will make a thing with two distinct calls to generate-unique-id.

kmkaplan
+4  A: 

You can do this using :constructor option of defstruct.

CL-USER> (defstruct (thing
                      (:constructor make-thing (&key a b (c (+ a b)))))
           a b c)
THING
CL-USER> (make-thing :a 1 :b 2)
#S(THING :A 1 :B 2 :C 3)

For more info, see CLHS entry for defstruct.

fionbio
Ah, this seems like what I was hoping for... thanks!
casper