* 8sync/rmeta-slot.scm (wrap-rmeta-slot): New variable.
* 8sync/actors.scm (build-actions): Switch from using make-rmeta-slot
to using wrap-rmeta-slot.
* doc/8sync.texi (Writing our own actors): Update documentation
to use #:init-thunk.
* 8sync/actors.scm (<actor>, define-actor, <hive>):
* 8sync/systems/irc.scm (<irc-bot>):
* demos/actors/robotscanner.scm (<warehouse-room>, <droid>):
* tests/test-actors.scm (<hi-on-init>):
* tests/test-rmeta-slot.scm (<kah-lassy>, <sub-lassy>): Update to
use #:init-thunk instead of #:init-value on actions slot.
"Construct an alist of (symbol . method), where the method is wrapped
with wrap-apply to facilitate live hacking and allow the method definition
to come after class definition."
- (make-rmeta-slot
+ (wrap-rmeta-slot
(list (cons (quote symbol)
(wrap-apply method)) ...)))
#:allocation #:each-subclass)
;; This is the default, "simple" way to inherit and process messages.
- (actions #:init-value (build-actions
+ (actions #:init-thunk (build-actions
;; Default init method is to do nothing.
(*init* (const #f))
;; Default cleanup method is to do nothing.
(action ...)
slots ...)
(define-class class inherits
- (actions #:init-value (build-actions action ...)
+ (actions #:init-thunk (build-actions action ...)
#:allocation #:each-subclass)
slots ...))
(prompt #:init-thunk make-prompt-tag
#:getter hive-prompt)
(actions #:allocation #:each-subclass
- #:init-value
+ #:init-thunk
(build-actions
;; This is in the case of an ambassador failing to forward a
;; message... it reports it back to the hive
#:use-module (srfi srfi-9)
#:use-module (ice-9 match)
- #:export (make-rmeta-slot
+ #:export (wrap-rmeta-slot
+ rmeta-slot-table rmeta-slot-cache
maybe-build-rmeta-slot-cache!
class-rmeta-ref))
;;; ;; Define a class with a meta-slot
;;; (define-class <kah-lassy> ()
;;; (entries #:allocation #:each-subclass
-;;; #:init-value
-;;; (make-rmeta-slot
+;;; #:init-thunk
+;;; (wrap-rmeta-slot
;;; `((foo . "bar")
;;; (baz . "basil")))))
;;;
;;; ;; Define a subclass
;;; (define-class <sub-lassy> (<kah-lassy>)
;;; (entries #:allocation #:each-subclass
-;;; #:init-value
-;;; (make-rmeta-slot
+;;; #:init-thunk
+;;; (wrap-rmeta-slot
;;; `((foo . "foo2")
;;; (peanut . "gallery")))))
;;;
(define (make-rmeta-slot table)
(%make-rmeta-slot table #f))
+(define (wrap-rmeta-slot table)
+ "In general, using wrap-rmeta-slot in combination with "
+ (lambda ()
+ (make-rmeta-slot table)))
+
;; Immutable and unique
(define %the-nothing (cons '*the* '*nothing*))
#:getter irc-bot-port)
(socket #:accessor irc-bot-socket)
(actions #:allocation #:each-subclass
- #:init-value (build-actions
+ #:init-thunk (build-actions
(*init* irc-bot-init)
(*cleanup* irc-bot-cleanup)
(main-loop irc-bot-main-loop)
(actions
#:allocation #:each-subclass
- #:init-value
+ #:init-thunk
(build-actions
(set-next-room
(lambda* (actor message #:key id)
(actions
#:allocation #:each-subclass
- #:init-value
+ #:init-thunk
(build-actions
(register-with-room
(lambda (actor message)
(define-class <sleeper> (<actor>)
(actions #:allocation #:each-subclass
- #:init-value (build-actions
+ #:init-thunk (build-actions
(*init* sleeper-loop))))
(define (sleeper-loop actor message)
We see some particular things in this example.
One thing is that our @verb{~<sleeper>~} actor has an actions slot.
This is used to look up what the "action handler" for a message is.
-We have to set the #:allocation to either @verb{~#:each-subclass~} or
-@verb{~#:class~}.@footnote{#:class should be fine, except there is @uref{https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25211,a bug in Guile} which keeps
-us from using it for now.}
+We have to set the #:allocation to either @verb{~#:each-subclass~}
+and use @verb{~#:init-thunk~}.@footnote{@verb{~build-subclass~} returns
+a thunk to be called later so that each subclass may correctly build
+its own instance. This is important because the structure returned
+contains a cache, which may vary from subclass to subclass based on
+its inheritance structure.}
The only action handler we've added is for @verb{~*init*~}, which is called
implicitly when the actor first starts up.
(create-friend #:init-value #f
#:init-keyword #:create-friend)
(actions #:allocation #:each-subclass
- #:init-value (build-actions
+ #:init-thunk (build-actions
(*init* hi-on-init-init))))
(define (hi-on-init-init actor message)
;; Define a class
(define-class <kah-lassy> ()
(entries #:allocation #:each-subclass
- #:init-value
- (make-rmeta-slot
+ #:init-thunk
+ (wrap-rmeta-slot
`((foo . "bar")
(baz . "basil")))))
(define-class <sub-lassy> (<kah-lassy>)
(entries #:allocation #:each-subclass
- #:init-value
- (make-rmeta-slot
+ #:init-thunk
+ (wrap-rmeta-slot
`((foo . "foo2")
(peanut . "gallery")))))