ENSUREF can be used to initialize &key and &optional key args more
conveniently.
Another name would be ORF, which looks funny to my eyes.
Another name would be INITIALIZEF, but this might open questions
regarding its relation to the object initialization machinery.
-T.
(defmacro ensuref (place thing &rest more &environment env)
"If PLACE evaluates to NIL, set it to THING. Otherwise, let it unchanged.
Examples:
(let ((a nil)
(b :foo)
(c (list 1 2 nil 4)))
(ensuref a :a
b :b
(third c) :c)
(values a b c))
==> :A, :FOO, (1 2 :C 4)
Notes:
(ENSUREF PLACE THING) is approximately equivalent to
(SETF PLACE (OR PLACE THING))
except that ENSUREF ensures (no pun indented) that PLACE is
evaluated only once, and except that PLACE isn't set at all if it
evaluated to NIL. (E.g. as a result, auxiliary methods of (setf foo)
generic functions aren't run in that case.)
"
(multiple-value-bind (gvars vals gstorevars setter getter)
(get-setf-expansion place env)
(when (second gstorevars)
(error "ENSUREF does not support setting multiple values ~
via the (VALUES ...) place."))
(if (null more)
(let ((gstorevar (first gstorevars))
(gtmp (gensym "CURVAL+")))
`(let ,(mapcar #'list gvars vals)
(let ((,gtmp ,getter))
(if ,gtmp
,gtmp
(let ((,gstorevar ,thing))
,setter)))))
`(progn (ensuref ,place ,thing)
(ensuref ,@more)))))