25

Ever heard of event-based programming? Nope? Well, here we are.

This is a software design pattern that revolves around controlling and defining state and behaviour. It has a temporal component (the code can rewind to a previous point in time), and is perfectly suited for writing state machines.

I think I could use some peer-review on this idea.

Here's the original spec for a full language: https://gist.github.com/voodooattac...

(which I found to be completely unnecessary, since I just implemented this pattern in plain TypeScript with no extra dependencies. See attached image for how TS code looks like).

The fact that it transcends language barriers if implemented as a library instead of a full language means less complexity in the face of adaptation.

Moving on, I was reviewing the idea again today when I discovered an amazing fact: because this is based on gene expression, and since DNA is recombinant, any state machine code built using this pattern is also recombinant[1]. Meaning you can mix and match condition bodies (as you would mix complete genes) in any program and it would exhibit the functionality you picked or added.

You can literally add behaviour from a program (for example, an NPC) to another by copying and pasting new code from a file to another. Assuming there aren't any conflicts in variable names between the two, and that the variables (for example `state.health` and `state.mood`) mean the same thing to both programs.

If you combine two unrelated programs (a server and a desktop application, for example) then assuming there are no variables clashing, your new program will work as a desktop application and as a server at the same time.

I plan to publish the TypeScript reference implementation/library to npm and GitHub once it has all basic functionality, along with an article describing this and how it all works.

I wish I had a good academic background now, because I think this is worthy of a spec/research paper. Unfortunately, I don't have any connections in academia. (If you're interested in writing a paper about this, please let me know)

Edit: here's the current preliminary code: https://gist.github.com/voodooattac...

***

[1] https://en.wikipedia.org/wiki/...

Comments
  • 3
    Seems the screenshot was not attached. Here it is!
  • 1
    After a quick read of your link at the bottom,isn't history an array where you can get any item from it between 0 and count value? So this requires saving to persistent storage and not only keeping in RAM. I'll need to dive deeper I like the idea it's just I'm on my phone now will check again and come back. Thanks for this post it's interesting
  • 2
    @gitpush You're welcome. And yes, history is an array that keeps track of the state with every tick.

    The spec allows your program to rewind in time, and you can set a limit on the number of states to keep. (and discard older states in the process)

    You can also disable history tracking and this rewinding feature completely by passing 0 to `history.limit`.
  • 1
  • 0
    @voodooattack well using noSql db and saving state as json in for example MongoDB allows going back in time to day 0, I wonder where we can make use of history of state
  • 1
    @gitpush If your state can be serialised to JSON (no class instances for example) then yes. You can pass the saved JSON state to the EventMachine constructor.
  • 0
    @voodooattack excuse my questions, what use will it give us if we can do point in time restore? I'm sorry I'm mostly a mobile dev we don't usually care about point in time restore
  • 2
    @gitpush Rewinding is for scenarios where you wish to restore an earlier state of the state machine. Here are some possible applications of rewinding:

    1. Your machine has entered a bad state: you can gracefully recover from such a situation by rewinding to a previous good state. (I'm considering adding a mechanism to pass along information from future states to past ones about what happened)

    2. Your program is traversing a tree: you rewind to the last branch once you reach a leaf node (but that'd also require the rewinding mechanism proposed in #1)

    3. Graph traversal in general, etc.

    I can't think of anything else right now, but someone can probably think of some other interesting applications they give it some thought!
  • 1
    @voodooattack I really like that state history and how we can get a dystr from anytime we want, but one needs to be sure to structure the state correctly or it's going to be a mess.

    What I also think of not sure if possible, but update past and see where present be due to that update, but again I can only think of that to be best suited for research like you said, it will be good to use with ML where they predicted based on history, and researcher can alter any point in past and see future
  • 2
    @gitpush Every time you return an object from an action you return a partial state that mutates the current state. So you only need to update what you require.

    Once you rewind, your program will naturally reach a new, but potentially different "present" again, but I can see some crazy applications for an inline evaluation technique (look ahead) like you're describing! You give a state and request the nested evaluation of the output while inside the "past" state. I can see how that would work.

    Especially because `EventMachine.exit(...)` accepts a final state object (optional) that can be returned in that case.
  • 2
    @voodooattack this is going to be an interesting weekend πŸ˜€
  • 1
    @gitpush Indeed!! I'm feeling super excited right now.

    Btw, I just implemented the "side-effect" mechanism here https://gist.github.com/voodooattac...

    This now rewinds and mutates the past state at the same time:

    ```
    @when(state => state.value >= 5) // this will only execute when `value` is >= 5
    exitWhenDone(s: State, m: TestMachine) {
    console.log(`finished on tick #${m.history.tick}, exiting`, s);
    if (m.history.tick === 5 && s.cycle < 10) { // rewind the program 10 times
    m.history.rewind(5, { cycle: s.cycle + 1 } ); // rewind the state machine with a side-effect
    }
    if (s.cycle >= 10)
    m.exit(); // exit the state machine
    }
    ```

    PS: I wish this site had markdown support. :(
  • 0
    @voodooattack Why don't you convert it to a project, I know typescript and can work on it in my spare time

    As for markdown, it does but you need to ake it a repo and not a gist if I'm not mistaken
  • 0
    @voodooattack and since it's in its early stages docs is important since there is too little to write about now it will be easy to write docs
  • 1
    @gitpush I'm already working on an npm package, this is just a copy for the curious.

    I will publish it as soon as I have enough features and the documentation/test coverage is good enough.

    Edit: Just so you know my reasoning for publishing early, I was so excited I couldn't stay silent about it. :D
  • 0
    @voodooattack do make sreto tag me when done πŸ˜€
  • 0
    Can you explain how is this different from Redux?
  • 0
    I think this is not so much "event based programming", and in fact more similar to logic programming.
    Let me explain:
    Event driven programming is usually called to programs where there are a fixed number of events, for example a mouse click, or a key press, not ones like yours where you could easily build an infinite loop.

    However, I think what your example is showing is closer to logic programming, in that you define a set of rules to solve a particular state, and it is the responsability of a language, library or runtime to decide on which order the rules have to be executed, to get the desired outcome.

    After all, what the program you show is doingid just to define a set of requirements, and how to solve those requirements, therefore allowing your library to decide how to solve each step.

    I am not saying this is not useful, just that the term used night not be the most appropriate one.
  • 0
    I'm not sure, but it sounds to me like event sourcing? E.g. here a reference https://confluent.io/blog/...
  • 0
    @aritzh That's a good point. There's also 'event-driven programming' as an existing concept which I think might be confusing.

    How about a new name then? How does 'recombinant logic programming' sound to you?

    I'd like any suggestions on this before I publish the reference implementation. (almost at 100% coverage now, still writing more tests)
  • 0
    @muliyul It's radically different from Redux in that states are constantly mutated from one tick to the next, and not by dispatching actions through action creators!

    There's also a discrete time system and a state history that's easy to access and rewind through.

    This is pattern is more suitable for real-time applications that run a fast/tight loop and state machines that you can interleave and step through one tick every cycle.

    The recombination feature would also make it good for developing AI agents that can acquire new behaviour dynamically. Because it's completely feasible to add the capability of self-modification during run-time and allowing the code to add and delete actions or to replace the conditions on them.
  • 1
    @Fenix Not exactly, from what I understood. Event sourcing is a way to store events describing an object's state in a database and evaluate the final state of said object by going through those records when it's need. Which I find very cool!

    But this is more like memory mapped-I/O, where your program has to keep polling a specific address in memory inside a tight loop to get the most recent mouse coordinates and button states, and react based on that new information:

    when(state => state.mouse.coordintates.withinBoundingBox(state.ui.button) && state.mouse.buttons.left) { ... mouse is hovering and is the button is pressed ... }

    Let's say this pattern would make low-level programming much easier. (but won't be fully discrete if used in such a manner)
  • 0
    @voodooattack that's very interesting however I'm wondering what is will look like for complex conditions
  • 0
    @muliyul This can be used to implement anything that can be implemented by using a state machine.

    It makes writing state machines *simpler*, which is very good news to any agent-based system that makes use of abstract logic trees for decision making. I'm just considering how to add activation inhibitors (like a way to turn off certain behaviours in some cases or make them mutually exclusive to better represent how real DNA works)

    Edit: I have the reference implementation fully working with full test coverage. I might just publish what I already have as an alpha for people to look at in the meantime.
  • 0
    @muliyul @gitpush Here's a working practical example of moderate complexity: https://gist.github.com/voodooattac...

    I'm all done with the first alpha reference implementation. I'm writing a godly amount of docs and examples right now. I'll upload it soon!
  • 2
    @gitpush As requested, here's the fully working implementation's repo: https://github.com/voodooattack/...

    It's on NPM and GitHub.
  • 0
    Can you gist a recombinant machine? For example primes that are less than a certain number?
  • 0
    @muliyul there are some basic recombination tests in this file: https://github.com/voodooattack/...

    I’m going to go to bed now but I‘ll try to implement something more practical with recombination in the morning when I wake up.

    I’ll mention you here when it’s done.
  • 0
    @voodooattack great will take a look at it πŸ˜€
Add Comment