In my first blog post in 2019, I asked “What if web programming were reimagined from the ground up?” My response at the time was to start building a new programming language for web applications. But as I have started implementing the Poly programming language from scratch, I have come to realize that the way Poly represents web applications — with content, styles, and dynamic behavior — might be the most challenging and intriguing part of the project.
Now as 2022 begins, I am exploring creating a unified representation for web applications and a set of tooling for compiling that representation into efficient, optimized websites. There could be a Poly programming language, at some point, that would compile into this representation; but other developers could also integrate with the Poly toolchain to enable their languages and frameworks to produce robust websites.
For more background and why I think this may be the most interesting path forward, read on:
Poly in the middle
Programming is a constant act of translation. There are many different programming languages out there, and there are tools called compilers that translate them into other formats — traditionally low-level languages the computer can run.
When human translators convert between languages, they may translate the source language to a mental encoding of what the words mean, then translate that mental encoding into the output language. Similarly, most compilers have a middle stage called an intermediate representation (IR), a tree-like structure that captures exactly what a program does.
In technical terms, a compiler is typically divided into a frontend and a backend. The frontend of a compiler is the first step that translates human-readable source code into an IR (similar to the term in web development, “frontend” here refers to user-facing code). The backend is the second step that converts the IR by traversing its tree-like structure, leveraging the connections amongst its branches, and finally producing the output in the target format.
Unlike most compilers, which output single-file executables that run on your device, Poly’s compiler will output websites made up of multiple files in HTML, CSS, and JavaScript. These three languages are used by web browsers to display, style, and give behavior to content.
In its ambition to unify the web languages, Poly’s IR must be able to capture the full nuance of a web application. At its simplest, a web application is a single page of unmoving text. But complexity scales quickly as web applications can have multiple pages, interactions with web servers and databases, dynamic styles, rendered graphics, and more.
This is all to say that I want to focus on this challenge and turn my attention to building out the Poly compiler backend instead of the Poly programming language (i.e. the Poly compiler frontend). Building out Poly’s backend is full of fun, incremental goals and mental exercises thinking how would you represent this in an IR? What would it take to represent a simple web page that shows a counter that increases as you hit a button? What about a web page that displays an editable todo list? A multipage personal portfolio website? And then what would the optimized output code look like for each case? Poly could have compiler options to enable a host of different output types and optimization strategies.
I am also excited thinking about what Poly’s backend, if implemented robustly enough, could enable. The Poly programming language need not be the only way to leverage the Poly backend. People could write their own compiler frontends for their programming languages and frameworks that target Poly’s IR, and then use Poly’s compiler backend for website generation. Poly could essentially act as a middle layer in other frameworks. Even visual tooling like website builders could leverage Poly to output finalized websites.
LLVM, a compiler toolset for desktop and mobile applications, is an example of this approach working well. LLVM provides an IR and an efficient, optimizing compiler that outputs machine code. New programming languages like Swift and Rust provide compiler frontends to LLVM’s IR and then utilize LLVM’s backend compiler to build applications targeting many different types of devices. In other words, LLVM has freed many programming language creators from having to think about the challenging step of optimizing machine code, allowing them to instead focus on the language itself. Ideally, Poly could do the same for web applications.
At this stage in my journey, I plan to pivot my focus to the Poly compiler backend. While a new human-readable programming language is still a likely step in Poly’s path, the core of the challenge building Poly is in the backend, and if done well, it could enable a whole host of exciting possibilities.