Next: Promise pipelining, Previous: Asynchronous message passing, Up: Tutorial [Contents]
Mistakes happen, and when they do, we’d like damage to be minimal. But with many moving parts, accomplishing this can be difficult.
However, Goblins makes our life easier. To see how, let’s
intentionally insert a couple of print debugging lines (with
pk
, which is pronounced and means “peek”) and then an error:
(define (^borked-cgreeter _bcom our-name) (define times-called (spawn ^mcell 0)) (methods ((get-times-called) ($ times-called 'get)) ((greet your-name) (pk 'before-incr ($ times-called 'get)) ;; increase the number of times called ($ times-called 'set (+ 1 ($ times-called 'get))) (pk 'after-incr ($ times-called 'get)) (error "Yikes") (format #f "[~a] Hello ~a, my name is ~a!" ($ times-called 'get) your-name our-name))))
Now let’s spawn this friend and invoke it:
goblins[1]> (define horatio (spawn ^borked-cgreeter "Horatio")) goblins[1]> ($ horatio 'get-times-called) ; => 0 goblins[1]> ($ horatio 'greet "Hamlet") ; pk debug: (before-incr 0) ; pk debug: (after-incr 1) ; ice-9/boot-9.scm:1685:16: In procedure raise-exception: ; Yikes ; Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.
Whoops! Looks like something went wrong! We can see from the
pk
debugging that the times-called
cell should be
incremented to 1. And yet…
goblins[1]> ($ horatio 'get-times-called) ; => 0
We will cover this in greater detail later, but the core idea here is
that synchronous operations run with $
are all done together as
one transaction. If an unhandled error occurs, any state changes
resulting from synchronous operations within that transaction will
simply not be committed. This is useful, because it means most
otherwise difficult cleanup steps are handled automatically.