>>>>> Pascal J Bourguignon <pjb@[EMAIL PROTECTED]
> writes:
[...]
>>> In this case, we have independent references in the *stocks* map,
>>> so the stock and item objects will always be reachable from
>>> *stocks*.
>> And, as I've noted above, the problem is completely the same when
>> there's a (item -> stock) map belonging to `shop'. Or, conversely,
>> when there's a (shop -> stock) map belonging to `item'.
> No. The difference, is as soon as you sell all the toys, all the toy
> shops lose references to them (assuming you remove the entries when
> the stock reach 0),
This effectively makes the (toy -> stock) mapping a principal
location for the toys.
The (shop, item) -> stock example wasn't probably sufficiently
generic, in a sense that I'm actually not interested in
``stock'' anymore whenever ``shop'' or ``item'' become
unreachable (other than through this mapping), while the example
may lead one to assume that I am.
> and therefore the toy items are not reachable anymore, and therefore
> the toy shops which are reachable only from the toy items are not
> reachable anymore and they can all be garbage collected.
> Of course, if a toy shop also sells some books, then it will be
> reacheable from these book items, and it won't be garbage collected.
> But this is what we want.
Actually, what I'm trying to implement is a kind of generalized
property list. In traditional Lisp implementations, IIUC,
property lists are implemented as a mapping, like: (symbol,
symbol) -> object.
However, symbols aren't actually good keys for mapping which
aren't to be stored. When a unique ``token'' object is needed,
it's more common to use a pair for it, rather than a symbol,
like (though the example below is of a little practical value):
(define *storage* (list))
(define (save obj)
(let ((token (list '*token*)))
(set! *storage* (cons (cons token obj) *storage*))
token))
(define (restore token)
(cdr (assq token *storage*)))
;; (let ((token-1 (save 'foo))
;; (token-2 (save 'bar)))
;; (values (restore token-1)
;; (restore token-2)))
;; => 'foo
;; 'bar
Note that if *storage* cannot be reached by the user of the
above library (e. g., if the module system is used in such a
way, or if `save' and `restore' are both defined within the
scope of `let' which bounds *storage*), there's no way for the
user of the library to access the mapping, except by using
`save' and `restore'. I. e., the (token -> object) mapping is a
``private'' one.
On the other hand, traditional (symbol, symbol) -> object
property lists are ``public'' in a sense that if one ``knows''
both symbols (or their written representations), the object they
are mapped to could readily be accessed. To allow this mapping
to be used for storing data ``private'' to the library, it
should be allowed to use arbitrary objects as keys, like:
(let ((object (make-object))
(token (list '*token*)))
(put object token 'value)
(get object token)) ;; => 'value
;; NB: 'value isn't accessible from outside of the `let' body
Here, it's necessary for the references to both `object' and
`token' contained within the `put'-mapping to be weak, since
otherwise it may be possible for both the `object' and `token'
to be stuck in the mapping even after they aren't reachable
anymore (e. g., after the `let' body in the example above.)
(Furthermore, `put' should associate appropriate finalizers for
both `object' and `token', in order for the invalidated weak
entries to be removed from the mapping, and thus for the `value'
to become unreferenced as well.)
Such ``weak'' mappings seem to give an op****tunity for the
programmer to associate additional state with arbitrary objects.
Probably the most im****tant is that the programmer may associate
such a state with already implemented objects. E. g., a ``page
width'' value may be associated with a ****t object to provide an
automatical wrap-around (though the programmer is then bound to
provide the alternatives for `write' and `display'.)
Or, consider:
(define *stick-token* (list '*stick-token*))
(define (make-method)
(let ((token (list '*token*)))
(lambda args
(assert (pair? args))
(if (and (pair? (cdr args))
(eq? *stick-token* (cadr args)))
(put (car args) token (caddr args))
(apply (get (car args) token) args)))))
(define (stick-method obj method proc)
(method obj *stick-token* proc))
(define foo (make-method))
(define (foo+list val . args)
(let ((l args))
(stick-method l foo (lambda any val))
l))
(define obj (foo+list 'x 1 2 3))
;; obj => '(1 2 3)
;; (foo obj) => 'x
[...]


|