Subtext 10 is well underway, but version 9 deserves some mention. I didn’t record a demo video as in the past, because I have concluded that medium fails to communicate in sufficient detail. In the future I am going to try the forms discussed in my last post. Unfortunately Subtext 9 has fallen between the cracks, and all it gets is this lousy blog post.
Here is the abstract for a presentation I gave last fall, back in the halcyon days of jetting off to international conferences.
Between spreadsheets and programming
The simplicity and utility of spreadsheets puts programming to shame. We believe the power of spreadsheets is that they offer a computational substrate: an autonomous artifact combining code and persistent data that is presented through a simple spatial metaphor. Can we invent other computational substrates with more general programming capabilities than spreadsheets, while retaining some of their magical simplicity? Subtext is an experimental computational substrate structured as a tree. Its key difference from conventional programming systems is that code is not a syntax tree but a semantics tree — a tree representing an execution trace. Execution is not, as we usually imagine it, the effects of a machine running in a sealed box, but rather is woven into the fabric of the substrate itself. Program execution is in plain sight of the developer, even while they edit it: What You See Is What You Execute. Perhaps surprisingly, programs can also benefit from observing their own execution, as when, for example, a parsing function’s execution is itself the parse tree. But there is a difficult research problem at the heart of this enterprise: finding a language whose execution semantics can be materialized as data structures within that language, done so simply and naturally that it supplants the need for syntax. After much trial and error, Subtext has converged on a design in which the execution of a block of straight-line code is a record datatype, conditionals form a discriminated union, a loop is an array, and calls are nested executions. This research is still in an early stage, and is presented in the spirit of provoking discussion and the hope of receiving advice.
In the demo I built a parser for a simple language of arithmetic expressions. It was coded as a recursive descent parser, which was simple because of the SNOBOL-like semantics of failure. The highlight of the demo was how the parser generated an AST. Normally the AST would be a recursive discriminated union (AKA sum), constructed as a return value of the parser. It is very boilerplate code, constructing back together the ASTs of the bits that have just been parsed apart. And plumbing the AST back through the parser is a pain. An advantage of parsing DSLs is that they can do all of this automatically for you
The highlight of the demo was showing how Subtext gives you “ASTs for free”. The trick is that because of the unification of code and data structures, the execution trace of the parser IS the AST. The recursive execution of the parser is physically a tree, and the conditional clauses trying to parse each kind of term are physically a sum. As a result, the execution trace of the parser is itself the AST, and this is made available to the code is a form of reflection.
Subtext 9 was progress for me: I finally figured out how to unify conditionals and sums after many failed prior attempts. I find this a deeply satisfying insight. On the downside, it turned out that thinking about executions as a data type was more abstract than I liked, and visualizing them in the programming environment was tricky. Subtext 10 will have a simpler way to expose these semantics. And advance in some other important directions, but that is another story.