[cello-devel] Unbound cells
Kenny Tilton
ktilton at nyc.rr.com
Wed Apr 14 07:54:14 UTC 2004
Thomas F. Burdick wrote:
>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 , at 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?
>
It might be the Dark Path of a long, well-respected, misbegotten
tradition of collapsing two attributes into one, creating /extra/ work
to save a slot. The first of the two slots is 'sign-in-status", with
three values: not-yet, failed, or succeeded. Then there is another slot,
which indicates who signed in (iff successful). We programmers have a
long heritage and habit of collapsing two values into one to save memory
or disk space (remember those?) by using some trick such as "use nil for
failure, unbounditude for not-yet, non-nil bound for the user", but my
experience has been that life gets a lot easier if I just let the diff
attributes be diff slots.
It is certainly tempting to "save one slot", but, again, my experience
has been that the consequent overloading saves a slot at the expense of
forever complexifying the code. I can't just say (ecase (sign-in-status
self) (:not-yet..)(:failed..)(:cool...))... I have to detect one
expected value with 'cell-unboundp and the other two with ecase, every
place in the code I need to access the user.
kt
--
Home? http://tilton-technology.com
Cells? http://www.common-lisp.net/project/cells/
Cello? http://www.common-lisp.net/project/cello/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Your Project Here! http://alu.cliki.net/Industry%20Application
More information about the cello-devel
mailing list