[cells-devel] Cells: Controlling the way kids are added to a parent ...

Kenny Tilton kennytilton at optonline.net
Thu Oct 30 23:16:13 UTC 2008


[hmmm... did you get my other response? This is a diff question, but you 
did not mention my other so I am concenred.]

Frank Goenninger wrote:
> ... and again a question related to this:
> 
> Suppose I have :
> 
> (defmd kid-test-2 (family)
>          (a-slot (c-in nil))
>          :kids (list (make-instance 'my-kid)
>                       (make-instance 'my-kid)))
> 
> Now - this completely bypasses the control mechanism inserted into fm- 
> kid-add - which is not what I wanted ;-)

Good point, another hole. In ACL and any CL supporting a full MOP, btw, 
you can supply an around method to (setf slot-value-using-class) which 
is the implementation of (setf slot-value) and /really/ control access. 
Anyway...

> So, I am asking myself if it would be better to insert the check into  
> the .kids observer ...

One big concern I have is, is this too late? Do you have any requirement 
to stop these sooner? ie, If you want to signal a condition that is 
fine, but recovering from it means also backing out the change and 
/that/ would be a lot of work at the late stage when the observer gets 
called.


> 
> I now have:
> 
> (defmodel family (model)
>   ((.kid-slots :cell nil
>      :initform nil
>      :accessor kid-slots
>      :initarg :kid-slots)
>    (.kids :initform (c-in nil) ;; most useful
>      :owning t
>      :accessor kids
>      :initarg :kids)
>    (registry? :cell nil
>      :initform nil
>      :initarg :registry?
>      :accessor registry?)
>    (registry :cell nil
>      :initform nil
>      :accessor registry)
>    ;; added: frgo, 2008-10-30
>    (control-hooks :cell nil
>                   :accessor control-hooks
>                   :initform (make-hash-table :test 'eql)
>                   :initarg :control-hooks)))
> 
> (defmethod get-control-hooks ((self family) hook-id)
>   (gethash hook-id (control-hooks self)))
> 
> (defmethod add-hook ((self family) id hook)
>   (setf (gethash id (control-hooks self)) hook))
> 
> (defun call-control-hook (hook self &rest args)
>   ;;; to be completed here
> )
> 
> (eval-when (:compile-time :load-toplevel)
>   (proclaim '(inline mklist))
>   (if (not (fboundp 'mklist))
>       (defun mklist (obj)
>         (if (listp obj)
>             obj
>             (list obj)))))
> 
> (defun run-control-hooks (id self &rest args)
>   (c-assert (typep self 'family))
>   (let ((hooks (get-control-hooks self id)))
>     (if hooks
>         (loop for hook in (get-control-hooks self id)
>            collect (call-control-hook hook self args)
>            into result
>            finally (return (mklist result)))
>         (mklist t))))
> 
> and
> 
> (define-condition cells-adding-kid-not-allowed-error (error)
>   ((text :initarg :text :reader text)))
> 
> (defun kid-add-allowed? (fm-parent kid)
>   (notany #'null (run-control-hooks 'fm-kid-add-control fm-parent  kid)))
> 
> (defun fm-kid-add (fm-parent kid &optional before)
>   (c-assert (or (null (fm-parent kid)) (eql fm-parent (fm-parent  kid))))
>   (c-assert (typep fm-parent 'family))
>   ;; Added: frgo, 2008-10-30
>   (if (kid-add-allowed? fm-parent kid)
>       (progn
>         ;; (trc "Adding kid to parent" kid fm-parent)
>         (setf (fm-parent kid) fm-parent)
>         (fm-kid-insert kid before))
>       (error 'cells-adding-kid-not-allowed-error
>               :text (format nil
>                             "ERROR: Kid ~s not allowed for parent  ~s." 
> kid fm-parent))))
> 
> - which is incomplete, of course, but shows the basic idea, or so I  hope.
> 
> Any thoughts if I should use the observer or do some clever slot  
> trickery using MOP ?

Ah, you were way ahead of me. The observer might be too late if you want 
this to be recoverable.

kt




More information about the cells-devel mailing list