Skip to content

Instantly share code, notes, and snippets.

@vilterp
Created June 23, 2015 02:13
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vilterp/befbf20eb67d8c3b74ec to your computer and use it in GitHub Desktop.
Save vilterp/befbf20eb67d8c3b74ec to your computer and use it in GitHub Desktop.
Plan for moving Reactor logic to Elm

Converting the Reactor frontend to Elm

As summarized in the reactor issue "WIP: convert JS to Elm", moving as much of the frontend of elm-reactor from JS to Elm as possible would have significant code quality benefits.

Step 1: Move View Code to Elm

As listed in the issue:

  • Use sliders from elm-html, not a custom native library
  • Move logic for toggling the sidebar and event blocker into Elm
  • Display errors with Elm, not with crazy JS
  • Possibly create trace canvas in Elm and render it with Graphics.Collage

Step 2: Move State & Time-Travel Logic to Elm

Sketch of types needed to represent the state (see debugger-implementation.js for current JS datastructures):

type alias DebugState =
    { runningState : RunningState
    -- , totalTimeLost : ?
    , events : Array Event
    , snapshots = Array Snapshot
    -- async callbacks?
    -- traces : ?
    , permitSwaps : Bool
    }

type RunningState
    = Running
    | Paused Time FrameIndex -- ?

type alias FrameIndex = Int

-- EVENTS

-- TODO: add trace updates

type alias Event =
    { id : SGNodeId
    , value : ElmValue
    , time : Time
    , watchUpdates : Dict WatchId ElmValue
    }

-- SNAPSHOTS

type alias Snapshot =
    { signalGraph : SGSnapshot
    , watches : WatchSnapshot
    }

-- signal graph

type alias SGSnapshot = Dict SGNodeId SignalValue

type alias SGNodeId = Int

type alias SignalValue =
    { id : Int
    , value : ElmValue
    }

-- WATCHES

type alias WatchSnapshot = Dict WatchId ElmValue

type alias WatchId = String

Sketch of tasks and ports needed to interact with the runtime system:

-- incoming

port events : Signal Event

-- outgoing

port captureSnapshot : Signal (Task e Snapshot)
port captureSnapshot = ...

port setToSnapshot : Signal Snapshot
port setToSnapshot = ...

port processEvents : Signal (Array Event)
port processEvents = ...

While the runtime system currently stores all of the state above, in the proposed refactor it would only:

  • Push events to the Elm code as they happen (into the events port)
  • Capture snapshots of the signal graph (handling the captureSnapshot port)
  • Set the signal graph to a given snapshot (handling the setAtSnapshot port)
  • Push a given event into the signal graph (handling the processEvents port)

Possible Step 3: Move swap handling to Elm

The sketch above only describes what happens while debugging the current version of the code. What happens when we want to swap? Currently the new code gets sent over a websocket, triggering the RTS to swap it in. If any of this was moved to Elm, the Elm code would:

  1. Initialize the websocket connection
  2. On new code being sent, send the new code to an output port.
  3. Replay user input from the beginning

This would require a new port: port newCode : Signal String

Performance Concerns

  • Converting snapshots between JS and Elm: Snapshots are captured by the RTS as JS data structures and need to be in JS form when we set the signal graph state to that snapshot. If they are stored in Elm, we need to convert to and from Elm on each of these operations.
  • Passing slices of the event list to JS (for processEvents), and appending lots of events to the event list in the DebugState value.
  • Drawing traces
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment