Next: Synchronous invocation, Up: Objects [Contents]
Objects can be spawned with the spawn
operator:
(spawn CONSTRUCTOR ARGS ...) ;=> <local-refr>
where CONSTRUCTOR
is a procedure which itself returns a
procedure representing an object’s current behavior. The
CONSTRUCTOR
is implicitly passed a first argument,
traditionally labeled bcom
, which can be used to change an
object’s behavior. The ARGS
are passed as the remaining
arguments to the constructor.
So for example, let’s say we have the following constructor:
(define* (^cell bcom #:optional val) ; constructor (outer procedure) (case-lambda ; behavior (inner procedure) (() ; 0-argument invocation (getter) val) ; (return current value) ((new-val) ; 1-argument invocation (setter) (bcom (^cell bcom new-val))))) ; ("become" ^cell with new value)
And so…
(define some-cell (spawn ^cell 42))
will bind val
to 42
.
Let’s look at the bcom
argument in depth. This is a capability
which allows the actor to change its own behavior. It must be called
in a tail position, since bcom
actually returns a datastructure
demonstrating that this object is choosing to change its value (part
of Goblins’ quasi-functional design.)
bcom
also can take a second argument, which will be returned
from the object’s invocation as a return value, allowing for both an
object change its own behavior and return a value at the same time
during an invocation.
The following actor represents a consumable object that returns a string explaining its current status:
(define (^drink bcom drink-name portions) (define (drinkable-beh portions) ; "-beh" is a common suffix for "-behavior" (lambda () (define portions-left (- portions 1)) (if (zero? portions-left) (bcom empty-beh (format #f "*GLUG!* You drink your ~a. It's empty!" drink-name)) (bcom (drinkable-beh portions-left) (format #f "*GLUG!* You drink your ~a. Still some left!" drink-name))))) (define (empty-beh) "Sadly, your glass appears to be empty!") (drinkable-beh portions))
Now, playing around at the REPL, we can see how this works:
> ,vr (define root-beer (spawn ^drink "root beer" 3)) > ,vr ($ root-beer) => "*GLUG!* You drink your root beer. Still some left!" > ,vr ($ root-beer) => "*GLUG!* You drink your root beer. Still some left!" > ,vr ($ root-beer) => "*GLUG!* You drink your root beer. It's empty!" > ,vr ($ root-beer) => "Sadly, your glass appears to be empty!"
As you can see above, bcom
is also a handy way to construct
state machines, as ^drink
moves from drinkable to empty as it
is consumed.
Next: Synchronous invocation, Up: Objects [Contents]