Kenny Tilton writes:
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.
My hesitation to do this is that I don't want worry about authentication outside of the authentication phase. Having an unbound slot seems a nice way to deal with it because it expresses the idea that asking for a user-id is not a valid question right now. It's perfectly legitimate for a user to not be logged in, but I want to make sure this has been checked.
I guess I could do something like this:
(defmodel my-handler () ((auth-status :accessor auth-status :initarg auth-status :initform (cv :not-authenticated)) (%user-id :accessor %user-id :initarg %user-id :initform (cv nil)) (user-id :accessor user-id :initarg user-id :initform (c? (assert (eql (^auth-status) :authenticated)) (^%user-id)))))
(defmethod authenticate ((request my-handler)) (let ((user-id ...)) (setf (auth-status request) :authenticated (%user-id request) user-id)))
However ...
Kenny Tilton writes:
On the other hand, Cells should not change Lisp unnecessarily.
It would be easy enough to do something such as (cv +unbound+) or just (cv) and then have the internal sm-install function invoke slot-makunbound instead of forcing the slot to be bound. Then one does not need a special test for cell-boundp (which sounds wrong anyway in re transparency).
But what about a rule that runs across an unbound cell/slot? I should think that does not generate an unbound error, rather the slot mediated by the rule should in turn be made unbound.
I guess echoing works OK, tho anyway doing this on the GUI slots will not get far since existing echos are not testing for unbounditude.
... I like this, because if you have rules that ultimately depend on an uncalculated value, you'll get an error when you try to ask for it.
The big hole is that slot-makunbound does not go through (setf /accessor/), and slot-makunbound-using-class is not portable, so we would need to lose some transparency and have an exported c-slot-makunbound function to make the slot unbound and kick off propagation (and confirm that the slot is c-variable mediated).
thoughts?
This is actually why I stopped at the cheesy hack level with what I had (that, and I wanted to get back to work). c-slot-makunbound could just dtrt if it's given an object that doesn't use cells; then it wouldn't be so bad to use it, you could just use it everywhere. You definately end out with a transperancy problem wrt CLOS one way or the other, unless you use the MOP.