One of the recent talks that stirred the blogosphere is the Inventing on Principle talk by Bret Victor, in which he shows how one can do programming with realtime results. What surprised me more than the talk itself was people’s reaction to the talk: I think many developers felt that what was shown was somehow new (whether technologically or ideologically).
I beg to differ. In fact, minus the fancy manipulation widgets, the demonstrated approach shown is already available to anyone wishing to have it.
The solution is to take a language that is either REPL-pliable or very quick to compile and then re-run the compiler/interpreter on every symbol change in the editor. For example, in F# we can wire up
FSI.EXE to re-run our script on any change. This is feasible performance-wise, and, coupled with a little code to intercept the standard output/error streams, you get a complete solution for rapidly prototyping any piece of code without having to explicitly compile something, manage the project, etc.
One place where the realtime approach is useful is numerics. Now we know that tools such as Mathematica, MATLAB etc. all basically do REPL, but that’s not nearly good enough. But what you can do is simply feed a whole file to an application to process wholesale. Then, simply observe any result you get.
The great thing about this is error handling during compilation. Making a mistake and then not getting the right result is very costly when compilation takes a long time and the availability of static analysis tools is poor. As a result, this ‘realtime’ approach really does save a lot of time and energy that would have otherwise been spent recompiling and cursing at yourself/the compiler/the universe.
And by the way, languages that support REPL are a lot better at outputting objects as text. For example, F# lets you write
printf "%A" xyz where
xyz can be a list, sequence, whatever. And it does output nicely formatted lists in a manner that, say, MATLAB easily can.
Let’s get back to F#/FSI for a moment. What’s interesting about feeding the ‘intermediate code state’ into the interpreter (which is the same as the compiler, by the way) is that we can augment the code passed in by putting in additional diagnostic statements. Not in the code, but at the postprocessing stage.
For example, we can take all method parameters and output them to the console. Or we can find every
let binding and output the object that’s being kept. And then, all of a sudden, all that ‘Inventing on Principle’ magic with illustrating changes in the intermediate variables suddenly becomes possible.
The applicability of this technique largely depends on the language. However, in many languages, it’s totally reasonable to adapt this approach. In particular, compiled languages that have a scripting counterpart (e.g., D) can be more amenable to this approach, whereas slow-to-compile languages such as C++ can benefit from substitution, the idea being that you prototype your code using a different language entirely. (Of course, extra effort will be required to make the conversion.)
Moral of the story: you already have capabilities for realtime programming, you just aren’t using them.