8

I don't think such support exists in current languages. I think what I want to do could be solved by a "workflow engine". But the problem I have with workflow's is generally they are:

  1. Declarative/verbose and I find a imperative style much more succinct
  2. Heavyweight, I'll have a lot of simple though diverse little state machines

I've investigated serializing iterators in C# but that doesn't get me exactly where I want to be. I'm current looking at putting together a DSL in Boo but not sure if I'll be able to get coroutine-like behaviour into Boo, and be able to serialize it as well.

Example

Here is limited fictional example of what I'd like to do. The main issue is that at any point in a routine you may need to get user input. The time between inputs could be very long so the state of service will need to be serialized to disk.

    def RunMachine(user)
      var lever = user.ChooseLever()
      lever.Pull()
      var device = CreateDevice(user)
      machine.Add(device)
      machine.Run()

   def CreateDevice(user)
      var color = user.ChooseColor()
      var shape = user.ChooseShape()
      return Device(color, shape)

Update

I have a working "engine" in CPython. It piggy-backs on the iterator/yield support in python. So code looks like this:

def escape(self, you):        
    roll = yield self.game.rollDice(you)
    if roll < 5:
        self.caughtAction(you)                  

Where rollDice can be interrupted. with some user action. CPython however doesn't serialize iterators.

Since the whole state of the game can be defined as a sequence of commands, I serialize the game state up to the point at where a coroutine started then the remaining list of commands. So to save/restore looks like this:

def dumpGameState(game):
    if gameState.partialState:
        return pickle.dumps({ 'partialState': game.partialState, 'partialInputs': game.partialInputs })

    return pickle.dumps(game)

def loadGameState(data):
    state = pickle.loads(data)

    if state.__class__ is Game:
        return state

    r = pickle.loads(state['partialState'])

    for input in state['partialInputs']:
        game.execute(**input)   
    return game

Current Investigations

I still find this unsatisfactory. As I end up having to use 'yield' on almost every method. I'd rather not have to specifically decorate a method. Also it quite fails at serialization.

Currently I'm investigating going a functional route, as functional languages seem to have better support for metaprogramming/DSL creation. Currently looking at

I'm hopeful that with strong enough metaprogramming facilities I can automate the state storage mechanism. Also, if I go the F# route, I'm pretty sure I can fall back on the "technique"/(hack) I used to serialize iterators.

Community
  • 1
  • 1
Joseph Kingry
  • 8,188
  • 4
  • 36
  • 52

5 Answers5

7

Funny that you should ask this today, and then later I read about Continuations in Mono. Looks like the kind of thing you're after. In particular there's a reference to Microthreading in Second Life, including this description:

SecondLife required that code be suspended at any point in time and that its entire state be serializable into a format suitable for storage into a database. Serialized state could then be restored at a different point in time or on a different computer (for example while moving from node to node).

Unless I've misunderstood you, this could be a good avenue to explore.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
6

I've found the best support for serializing coroutines appears to be in Lua via the Pluto library.

I triend Mono 2.6, but couldn't get coroutines working. I then experimented with Python/IronPython for awhile, but serialization support was lacking.

Now with Lua I'll have to interface via P/Invoke from .NET to Lua which prove to be a challenge to get working on both Linux and Windows, but ultimately if I'm looking for a scripting language to support a game, probably best to use what is already popularly being chosen.

Update

I ended up abandoning Lua for the time being. I was getting too bogged down in integration issues. I went back to Python. I'm using python yield expressions for my coroutines, and working around the issue that pickle doesn't support generators.

In my case, the program state doesn't always have active coroutines, which means sometimes I can pickle the state. Otherwise I store the last pickle state, and a 'replay history' of the actions since. Then restoring state is just unpickling the last state, and replaying any actions.

Joseph Kingry
  • 8,188
  • 4
  • 36
  • 52
1

You might want to take a look at Windows Workflow:

http://msdn.microsoft.com/en-us/netframework/aa663328.aspx

It is meant to be used in a manner like this, with the ability to persist a workflow if there is inactivity on it, as well as the ability to restart it.

While technically it isn't language support, it should get the job done.

casperOne
  • 73,706
  • 19
  • 184
  • 253
  • 1
    Yeah, I tried to specifically point out I was trying to avoid a XML heavy, declaritive work flow engine, eg. specifically Windows Workflow. – Joseph Kingry Apr 09 '09 at 16:38
1

Are you looking for continuations?

In any language which supports closures, it is possible to write programs in continuation passing style and manually implement call/cc.

call/cc being call-with-current-continuation.

Svante
  • 50,694
  • 11
  • 78
  • 122
  • I believe coroutines are something you could build on top of continuations. Coroutines allow for a much more natural expression of intent IMHO. – Joseph Kingry Apr 09 '09 at 16:47
  • But I return to the issue, even given continuation support in a language, can you serialize them? – Joseph Kingry Apr 09 '09 at 16:47
  • Some. For example, http://wiki.apache.org/cocoon/RhinoWithContinuations#head-d6b2435bbd91bef7f61324cd35775998da035f7a – ephemient Apr 10 '09 at 21:11
  • In fact, the design of the http://www.seaside.st/ Seaside web framework depends upon serializable continuations. – ephemient Apr 10 '09 at 21:12
0

The latest version of Java includes Rhino, a javascript interpreter with support for serializeable continuations. There's also Pluto+Lua, which I'm investigating now.

I'd like to hear about what path you ended up taking, as serializeable continuations are important to the http://weaverengine.com project.

Lilith River
  • 16,204
  • 2
  • 44
  • 76