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
Transactionality 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.