Previous: , Up: Objects   [Contents][Index]


5.1.5 define-actor

Syntax: define-actor (object-name var …

[#:optional vardef …] [#:key vardef …]) [#:restore procedure] [#:portrait thunk] [#:version version] [#:frozen] [#:upgrade migrator] [#:self name] body …

Defines a goblins object with object-name. The argument syntax is that of define* or lambda* in that it takes #:key and #:optional, however it does not support #:rest, nor #:allow-other-keys. The object by default is redefinable which aids in live hacking.

When #:restore is given with a procedure, that procedure is called to restore the actor upon rehydration from Goblins persistence system. It’s called with the initial argument being the version of the portrait data followed by the portrait data given by the portrait data. When no restore function is provided the default behavior of dropping the version and applying the other arguments to the constructor is used.

When #:portrait is given with a thunk, that is called to produce the object’s self portrait in order to persist it. This thunk is run within the body of the object so all arguments to the object are available. When no portrait is given, the self portrait will match the arguments provided to the constructor.

When #:version is provided it will tag the portrait with that version.

When #:frozen it does not define the object as a redefinable object (useful for live hacking) and prevents #:restore being used. Frozen objects have a slight performance improvement on spawning.

When #:upgrade is provided, it uses this to migrate the portrait data to the newest version. This is designed to work with the migrations macro, however can be used on its own. This cannot be used in combination with #:restore.

When #:self is provided with a identifier, that identifier is bound to the refr of the actor itself.

Here is an example defining a simple cell object, portrait would be the val:

(define-actor (^cell bcom #:optional val)
  (case-lambda
    ;; Called with no arguments; return the current value
    [() val]
    ;; Called with one argument, we become a version of ourselves
    ;; with this new value
    [(new-val)
     (bcom (^cell bcom new-val))]))

Here’s an example of a thermostat which takes in the temperature as a cell and a reference to a heater. It defines a portrait which removes the value from the cell. It specifies a version of 1, as it needs to do version upgrade. Finally in the restore function it matches on the version and converts from Celsius to Kelvin if it’s the original version and spawns the ^thermostat with the cellified set temperature:

(define-actor (^thermostat bcom set-temp-cell heater-refr)
  #:portrait (lambda ()
	       (list ($ set-temp-cell) heater-refr))
  #:version 1
  #:restore (lambda (version set-temp heater-refr)
	      ;; Version 0 used C, convert to kelvin
	      (define maybe-converted-temp
		(match version
		  [0 (+ set-temp 273.15)]
		  [1 set-temp]))
	      (spawn ^thermostat
		     (spawn ^cell maybe-converted-temp)
		     heater-refr))
  (methods
   [(set-temp new-temp) ($ set-temp-cell new-temp)]
   ;; Invoked with current room temp
   [(tick current-temp)
    (if (< current-temp ($ set-temp-cell))
	(<-np heater-refr 'turn-on)
	(<-np heater-refr 'turn-off))]))

NOTE: this actor could have kept the temperature in the cell, there’s usually no reason to unpack values like this, it’s just for example purposes.


Previous: Object reference predicates, Up: Objects   [Contents][Index]