I have a couple models where I'd like to have unbound slots that normally have cv cells in them. NIL is a valid value, so I can't just say "nil is the invalid value." What I'm doing is using a special invalid-value object when I'd normally have an unbound slot:
(defconstant +unbound+ '+unbound+) (deftype %nil () '(or nil (eql +unbound+)))
(defmacro define-unbound-methods (&body slot-specs) (loop for (class slot opt-accessor) in slot-specs for accessor = (or opt-accessor slot) collect `(defmethod ,accessor :around ((object ,class)) (let ((value (call-next-method))) (if (eq value +unbound+) (error 'slot-unbound :instance object :name ',slot) value))) into methods finally (return `(progn ,@methods))))
(defun cv_ () (cv +unbound+))
(defmodel my-handler (araneida:handler) ((user-id :accessor user-id :initarg user-id :initform (cv_) :documentation "user id or NIL if the user didn't supply valid credentials") (homepage :accessor homepage :initarg homepage :initform (c?_ (aif (id (^user-id)) (make-homepage-for-user id) (create-user-account))))))
(define-unbound-methods (my-handler userid))
(defmethod handle-request-authentication ((handler my-handler) method request) (setf (user-id h) ...))
If user-id is unbound, it means that authentication hasn't been performed yet, so it would be a program error to try to use its value at that point.
It seems like it wouldn't be too hard to put the concept of unbound slots into Cells itself, so that storing the unbound-slot value would work fine, but reading it would signal a slot-unbound error. Add cell-makunbound and cell-boundp, and it would be the normal CLOS semantics again.
Does this sound like a good idea? Or is there a more idiomatically Cells way of doing this, and I'm wandering too far down The Dark Path of Lazyness?