Ok, hold on, I just realize there was no way this could work:
At the time the (c? ...) is evaluated, the (c-in ..) cell it is supposed to depend on does not even exist, so how should c? possibly establish a dependency to that?
Since I am still looking for a cell-aware store, I suggest something like this:
(c?-with (obj :foo *store* 'nothing) (value obj))
with
(defmacro c?-with ((obj key store &optional default) &body body) ...)
where key is looked up in store; if it exists, body is executed with obj bound to the corresponding object. If not, default is returned. The trick is to delay the execution of body until key in store is created, only then executing the body, and having cells pick up the dependencies.
So basically we want *store* to be defined before c?-with is evaluated -- and once it is, it will check whether key is already present in there. If it is not, it pushes a closure into a hash table on key in store. Then, if whenever an object is added to store, store will check whether something is in the c-with-queue hash table, and evaluate the stored closures if any. These in turn will kick their c?-with ruled cells, which can then be initialized just like normal cells.
The big question will be: How do we do the delay so that the cell does not get optimized away prematurely? That is, how do we make sure, that the cell first duly registers itself with store, then returns the default, and finally establish the proper dependencies when the stored closure gets kicked by the store?
Ideas welcome.
Cheers, Peter
On Wed, Apr 16, 2008 at 5:26 PM, Peter Hildebrandt peter.hildebrandt@gmail.com wrote:
While working on the hash-table lookup for md-names (as an alternative to fm-other) I came across an interesting phenomenon: Some rules die, others don't. Following the XP idea for RFEs, I'll try to present a test case:
(defpackage :c-test (:use :cl :cells :utils-kt)) (in-package :c-test)
(defparameter *hash* (make-hash-table)) (defun val (name) (bwhen (obj (gethash name *hash*)) (value obj)))
(defparameter *m1* (make-instance 'model :value (c? (bif (v (val :foo)) (1+ v) 'nothing)))) (assert (eql (value *m1*) 'nothing))
(setf (gethash :foo *hash*) (make-instance 'model :value (c-in nil)))
(defparameter *m2* (make-instance 'model :value (c? (bif (v (val :foo)) (1+ v) 'nothing))))
(assert (eql (value *m1*) 'nothing)) (assert (eql (value *m2*) 'nothing))
(setf (value (gethash :foo *hash*)) 42) (assert (eql (value *m1*) 43)) ;;; #### FAILS #### (assert (eql (value *m2*) 43)) ;;; ok
(setf (value (gethash :foo *hash*)) 17) (assert (eql (value *m1*) 18)) ;;; #### FAILS #### (assert (eql (value *m2*) 18)) ;;; ok
;;; or with a list
(defparameter *list* nil) (defun valb (name) (bwhen (obj (assocd name *list*)) (value obj))) (defparameter *m1b* (make-instance 'model :value (c? (bif (v (valb :foo)) (1+ v) 'nothing))))
(assert (eql (value *m1b*) 'nothing))
(push (cons :foo (make-instance 'model :value (c-in nil))) *list*)
(defparameter *m2b* (make-instance 'model :value (c? (bif (v (valb :foo)) (1+ v) 'nothing))))
(assert (eql (value *m1b*) 'nothing)) (assert (eql (value *m2b*) 'nothing))
(setf (value (assocd :foo *list*)) 17) (assert (eql (value *m1b*) 18)) ;;; #### FAILS #### (assert (eql (value *m2b*) 18)) ;;; ok
(setf (value (assocd :foo *list*)) 42) (assert (eql (value *m1b*) 43)) ;;; #### FAILS #### (assert (eql (value *m2b*) 43)) ;;; ok
An interesting indicator might be that the first call to (value *m1*) returns two values, 'nothing and nil -- does that mean that cells somehow realizes there that this cell can be optimized out?
And -- more importantly -- how can I tell cells not to optimize away the ruled cell in *m1*/*m1b*?
Thanks, Peter