Next: Promise pipelining, Previous: Asynchronous message passing, Up: Tutorial [Contents][Index]
Mistakes happen, and when they do, the damage should be minimal. But with many moving parts, accomplishing this can be difficult.
However, Goblins makes life easier. To see how, 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 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! You 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
This is covered 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.