Live Programming for Event-based Languages
Christopher Schuster, Cormac Flanagan
University of California, Santa Cruz
{cschuste, cormac}@ucsc.edu

Traditional Edit-Compile-Restart-Cycle

Live Programming Environment

Live Edits to Running Programs

Classic Problem: Dynamic Software Updating, Hot Swapping, etc.

No General Solution! — Design Space of Alternatives

Desired behavior after code updates

  • Replay all events since program start
  • Continue executing with potentially inconsistent state

Data might need to be updated along with code

  • Production systems: specify patches/data migrations manually
  • Debugging/live programming: minmize impact on development flow

Code Updates and Execution State

Challenge 1: Call Stack

var i = 0;
function inc() { i++; }
inc(); i+=2;
console.log(i);

Where does inc() return to?

Challenge 2: Output out of date

<div>
  <button>Click Me</button>
  <span>Count: 0</span>
</div>  Clicks:

Count: 0
<script>
var i = 0;     "mouseover"
$("button").on("click", function() {
  $("span").html("Count: " + (++i));
});              "Clicks: "
</script>

Challenge 3: Closures in State

<div>
  <button>Click Me</button>
  <span>Count: 0</span>
</div>

<script>           (i,n)
function mkCounter(i) {      i+=n
  return function() { return ++i; };
}                      (0,2)
var counter = mkCounter(0);
$("button").on("click", function() {
  $("span").html("Count: " + counter());
});
</script>

Challenge 4:
New Code Incompatible with State

<div>
  <button>Click Me</button>
  <span>Count: 0</span>
</div>

<script>
var i = 0;[];
$("button").on("click", function() {
  i.push(Date.now());
  $("span").html("Count: " + (++i));i.length);
});
</script>

Live Programming in
Event-based Languages

Single-threaded event loop (e.g. JavaScript)

  • Treat code updates as events
  • No code updates during event processing

⟶ No Active Call Stack or Program Counter

Separate Event Handling
and Rendering

init :: () ⟶ State

  • Computes initial application state

handle :: Event × State ⟶ State

  • Processes an event and returns new application state

render :: State ⟶ Output

  • Determines output based on the current state

Contraints

  • render should not change state
  • The application state should not contain function values

Separate Event Handling from Rendering: Example

var i = 0;

function inc() { i++; }

function render() {
  return (
    <div>
      <button onclick={inc}>Click Me</button>
      <span>Count: 0{i}</span>
    </div>);
}

Implementation 1/2

Code gets parsed, checked, rewritten and evaluated upon each change

Rewriting turns global references to access a managed state object

  function inc() { i++; }
⟶ function inc() { ENV.state.i++; }

Variable initializations will be extracted to an init function

  var i = 0;
⟶ function init() { ENV.state.i = 0; }

JSX (JavaScript with inline-XML) will be expanding to regular JavaScript (other ways of generating HTML would work equally well)

  var i = <p>Hello!</p>;
⟶ var i = {type: 'p', children: ['Hello!']};

Implementation 2/2

After each event,

  • the state will be checked for function values
  • a clone of the state will be saved for time travel
  • render is called with an immutable clone of the state
    (using Object.freeze)

UI for accessing previous code versions and states

Github Repository: https://github.com/levjj/rde/

Online Live Demo: https://levjj.github.io/rde/

Demo

Navigating history of execution and code

Summary

Challenge Proposed Solution
Updating running functions Use single event loop to update code ✓
Outdated visual feedback Seperate rendering from event handling ✓
Updating function values/closures Restrict application state !
Inconsistencies between state and code Programmer may need to restart ✗

Enables live programming, time travel and continous feedback

Implemented in JavaScript but works for any event-based language

Future Work

Restricting function values in the state may be too strong (e.g. OOP)

Use programming language features to ...

  • enforce constraints (static analysis, contracts, etc.)
  • optimize performance (incremental computation, copy-on-write, etc.)

Improve tool support, e.g. programming by example

  • Write render function by direct manipulation in the output
  • Write event handling function by providing examples of states before and after an event

Related Work

Literature

  • Burckhardt, Fahndrich, de Halleux, McDirmid, Moskal, Tillmann, and Kato. It’s Alive! Continuous Feedback in UI Programming. PLDI ’13.
  • McDirmid. Usable Live Programming. Onward!'13.

Inspirations

  • Bret Victor. Inventing on Principle. 2012.

Smalltalk/Squeak

Elm

React/Redux

Thank you!

Degenerated Case: DOM as part of Application State

var i = 0;
var dom = (
  <div>
    <button onclick={inc}>Click Me</button>
    <span>Count: 0</span>
  </div>);

function inc() {
  dom.find('span').html = 'Count: ' + (++i);
}

function render() { return dom; }

←   /   →