Before any of the machinery, it is worth being clear about what I actually want from this language, and about a few choices that look unusual at first and end up paying for themselves many times over.
It is a long list to fit into a small package, but the first version of Program manages all of it:
- Broadly applicable.
Interfaces, servers, games, all in the same language.
- Beginner-friendly.
A small number of well-defined commands, no thicket of funny symbols, and no mathematical thinking required to be productive.
- High-level and declarative.
Write what the application should be, and leave the platform to work out how.
- Composable interactivity.
Drop an interactive component in by changing code only where it is added; no global state management, no event handlers threaded up through the app.
- A small definition.
Only a handful of essential keywords; everything interesting lives in the modules.
- The happy path.
You write the simple, successful case. Loading, errors, retries and the other cross-cutting concerns are the system's job, not clutter spread through your code.
- Batteries included.
Interface, animation, networking, files, enough to build real applications out of the box.
- Asynchronous-agnostic.
Your code should not care whether something is synchronous or asynchronous; on different platforms the same code might be either.
- Capability-based.
Every reach outside the program is provided by the runtime - or not, if you want a locked-down sandbox - and any capability can be overridden with your own implementation, for testing or filtering.
- Polyglot.
Run it through an interpreter, or render it into many languages, with new targets easy to add thanks to the simple underlying format.
- Portable.
Both the code and a running program have a simple data structure, so a snapshot can be resumed later, or on an entirely different machine.
- Diagram-friendly.
That same simple format means programs can be shown and edited as diagrams, with whole interactive components as blocks.
- Completely understandable.
If you want to, you can learn exactly how the whole thing works, well enough to build it yourself, with no compiler background.
That is a lot to ask of one small language, and the only way it fits is that these goals are not really separate. They mostly fall out of the same few decisions. In the posts that follow I'll build those up, layer by layer, and show how each goal is paid for by the one underneath it.