title: Time travel debugging in Spritely Goblins, previewed through Terminal Phase
date: 2020-01-23 14:55
author: Christine Lemmer-Webber
tags: goblins, spritely, terminal phase
slug: goblins-time-travel-micropreview
---

![Time travel in Spritely Goblins shown through Terminal Phase](https://dustycloud.org/gfx/goodies/terminal-phase-goblins-time-travel.gif)

Okay, by now pretty much everyone is probably sick of hearing about
[Terminal Phase](https://gitlab.com/dustyweb/terminal-phase).
[Terminal Phase this](https://dustycloud.org/blog/terminal-phase-1.0/), and [Terminal Phase that](https://dustycloud.org/blog/terminal-phase-prototype/)!
Weren't you getting back to other hacking on
[Spritely Goblins](https://gitlab.com/spritely/goblins), Chris?
And in fact I am, I just decided it was a good idea to demo one of the
things that makes Goblins interesting.

What you're seeing above is from the
[experimental tt-debugger branch of Terminal Phase](https://gitlab.com/dustyweb/terminal-phase/tree/tt-debugger)
(not committed yet because it's a proof-of-concept, and not as clean
as I'd like it to be, and also you need the "dev" branch of
[Goblins](https://gitlab.com/spritely/goblins/tree/dev) currently).
When the user presses the "t" key, they are presented with a menu
by which they can travel backwards and forwards in time.
The player can select a previous state of the game from every two seconds
and switch to that.

Here's the cool part: I didn't change a single line of game code to
make this occur.
I just added some code around the game loop that snapshotted the state
as it currently existed and exposed it to the programmer.

What kind of time sorcery is this?

![Dr. Who/Dr. Sussman fez comparison](https://dustycloud.org/tmp/dr_sussman.png)

Well, we're less the time-lord kind, more the functional programmer
kind.
Except, quasi-functional.

If you watched
[the part of the recent Terminal Phase video I made that shows off Goblins](https://www.youtube.com/watch?v=wxt2dqqulQc&feature=youtu.be&t=1746)
you'll remember that the way that objects work is that a reference
to a Goblins object/actor is actually a reference that indirectly
refers to a procedure for handling immediate calls and asynchronous
messages.
Relative to themselves (and in true
[actor fashion](https://en.wikipedia.org/wiki/Actor_model#Fundamental_concepts)),
objects specify first their initial version of themselves,
and later can use a special "become" capability to specify a future version of
themselves.
From the perspective of the actor, this looks very functional.
But from the perspective of one object/actor performing a call against another
object/actor, it appears that things change.

Here is the simplest example of such an object, a cell that holds a
single value:

``` scheme
;; Constructor for a cell.  Takes an optional initial value, defaults
;; to false.
(define (^cell bcom [val #f])
  (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))]))
```

If you can't read Racket/Scheme, not a big deal; I'll just tell you
that this cell can be called with no arguments to get the current
value, and with one argument to set a value.
But you'll see that in the former case, the value we would like to
return to the caller is returned; in the latter case, we return the
handler we would like to be for handling future messages (wrapped up
in that `bcom` capability).
In both cases, we aren't performing side effects, just returning
something.. but in the latter case the kernel observes this and updates
the current transaction's delta reflecting that this is the "new us".
(Not shown here but supported: both becoming a new handler *and* returning
a value.)

Without going into details, this makes it extremely easy to accomplish
several things in Goblins:

 - **Transactionality:** Each "turn" of an event loop in Goblins is
   transactional.
   Rather than being applied immediately, a transaction is returned.
   Whether we choose to commit this or not is up to us; we will
   probably not, for instance, if an exception occurs, but we can
   record the exception (a default event loop is provided that does
   the default right-thing for you).
 - **Snapshotting time:** 
   We can, as shown above, snapshot history and actually run code against
   previous state (assuming, again, that state is updated through the
   usual Goblins actor "become" means).
 - **Time-travel debugging:**
   Yeah, not just for Elm!
   I haven't built a nice interface for it in the demo above, but it's
   absolutely possible to expose a REPL at each snapshot in time in
   the game to "play around with" what's happening to debug difficult
   problems.

This is only a small portion of what makes Spritely Goblins interesting.
The really cool stuff will come soon in the distributed programming stuff.
But I realized that this is one of the more obviously cool aspects of
Spritely Goblins, and before I start showing off a bunch of other
interesting new things, I should show off a cool feature that exists in
the code we already have!

Anyway, that's it... I hope I gave you a good sense that I'm up to
interesting things.
If you're excited by this stuff and you aren't already,
[consider donating](https://www.patreon.com/cwebber) to keep this
work advancing.

Whew!
I guess it's time I start writing some docs for Goblins, eh?
