David Brandt · trains of thought

Programming languages · The lowest common denominator, part 1 of 4

One language, transpiled to all the others

LCD, the language I never wrote

Seeded 2001 Written November 2026

Around 2001 I was fed up with writing the same business rules over and over.

They were never interesting rules. How an invoice is totalled. Which orders need someone to approve them. When a discount applies. The kind of thing a business could explain in a paragraph and then spend a decade being slightly wrong about. The trouble was not writing them. The trouble was writing them again, and again, because each execution environment that needed the rule ran on a different technology stack.

There would be a copy in C. Several copies in C++, because C++ was not one environment but several: MFC had its own idea of what a string was, Qt had another, and plain C++ with the standard library had a third. There was Java on the application server, and PL/SQL in the database, because the batch jobs and the reports ran next to the data. And probably Pascal, since Delphi was what a lot of people built their clients in.

Every copy was written by hand, sometimes by me and sometimes by someone else, in a different idiom, with different defaults for rounding, for null, for what dividing two integers means. On the day they were written they agreed. From then on they drifted. A fix in one copy was a bug report waiting to happen in all the others.

What I wanted was obvious, or felt obvious: write the rule once, in one language, and have it turn up in every one of those environments as code that belonged there.

I called it LCD.

The day job

LCD came straight out of my day job.

From 1998 to 2002 I worked at OZ, on iPulse, a communication and presence system: buddy lists, who is online, messaging, routing. My part was the plumbing underneath, the RPC system. Marshalling code, proxies and stubs, parsers, network streaming, and code generators, for several programming languages and environments at once. Most of it was in C++, Perl and Java.

A code generator for RPC is a machine for writing one thing once and getting it in several languages. You describe a message, and out come a C++ struct, a Java class and whatever Perl wants instead, with the code that turns each of them into bytes and back. The shape of the data is the same everywhere because nobody wrote it more than once.

The RPC layer talked to many different contexts, and every one of them needed the same logic. The generators gave them that logic without anyone writing it twice. If that worked for the RPC logic, it could work for the business rules too.

The name

Lowest common denominator is usually an insult. Here it was a specification.

The language would contain what every target could express, and nothing else. If C++ and Java could both do something, and do it the same way, it was in. If one of them couldn't, it was out, or it was given a meaning that both of them could carry. And the same test would have to hold for every other language: Python, which was already around, C#, which arrived the year after, then Go, TypeScript and Rust, and behind them the niche and the obsolete, the languages that still quietly run a payroll somewhere. The name was meant to keep me honest: whatever LCD was, it was not going to be a superset with a large runtime pretending to be every language at once.

Transpiled, obviously

I was pretty obsessed with transpiling it. Not compiling it to some common machine, not running it on a virtual machine of its own: turning it into source code in each target's own language.

That was not the fashionable answer in 2001. The fashionable answer was Java's: one runtime, everywhere, write once and run anywhere. Oracle had even put a Java virtual machine inside the database. The PL/SQL kept coming anyway, because the people who worked in the database wrote PL/SQL, and their tools, their debuggers and their habits all assumed it.

So the output had to be code that the people in each environment would own. A Java developer should open the generated file and see Java, the kind a careful colleague might have written. A database developer should see a PL/SQL package. Nobody downstream should have to know that LCD existed in order to read, debug or profile what it produced.

I had a less practical hope for it, too. Code formatters weren't in everyday use yet, and linters were a rarity out in the boondocks of Reykjavík, so a code review could turn into a flamewar over braces, indentation and names. If every environment got the code in its own style, why not every person? Write the code the way you like it, read it the way you like it, and there is nothing left to argue about.

Part 2 is about why this one choice turned out to shape almost everything else.

What I knew

Looking back at the list of languages I had used by then, I can see why I never believed in one denominator for everything.

I had written C++ for years, in more than one job, and Java and Perl in the one I had then. Along the way, at school, at work and in between, I had spent time with COBOL, Ada, Prolog, Lisp, assembly, BASIC, Pascal and LPC, the language the LPMud game servers ran on. Plus C, of course, and, because work demanded it, PL/SQL.

If you take the common denominator of all of those, you get very little. Prolog has no assignment. COBOL, at the time, had no functions you could define yourself. SQL has no steps at all, only sets. Assembly doesn't have types. A language that worked in all of them could describe data and almost nothing else.

I knew that. The interesting question was never whether one LCD could cover everything. It was how far one could get, and with what.

What it was meant to be

LCD was imperative: variables, assignment, conditions, loops, functions and procedures, records. All the traditional concepts, nothing exotic. Its memory was managed, which in those days meant one of two things: Java's garbage collector, or reference counting in C++. It had the classical data types and the kind of standard library you would expect to find anywhere: text, numbers, dates, collections.

It was for business logic. It would not draw windows, open files or talk to the network. The program around it would do that, and hand LCD what it needed to make a decision.

And it was meant to be transpiled into C, C++ in its various frameworks, Java, and every other programming language, past, present or future. Perl was on my mind as well, the way it was on everyone's mind in 2001: as the nightmare you woke from at three in the morning, crying, in a cold sweat, having dreamt that you had to change somebody else's regular expressions. LCD was going to let Perl sleep.

Why it stayed a dream

It never got further than that. No grammar, no transpiler, no decisions about how to close the gaps between targets: their type systems, their memory models, their ideas of what a record or a list is. I didn't write anything down.

I dropped it for an unglamorous reason. It wasn't something I wanted to spend my time on, and in those days it would have taken a massive amount of time. One person, several transpilers, a runtime library for every target, and no way to know whether any of it was right until all of it was finished.

Why write it down now

Because the idea never went away.

It has kept coming back ever since, these days as a language I call Y. I have never seriously sat down and built it. I have started it and shelved it more times than I can count. The oldest attempt that left anything in writing is YAPL, from 2019, which early on described itself as a transpiler to "all machines": LCD again, nearly twenty years later, under a different name. The latest version of Y has put transpiling, and the features that languages have in common, back in the spotlight, and that has had me reminiscing about LCD.

The rest of this series works out what LCD would have had to be:

  1. One language, transpiled to all the others. This part.
  2. Levels of denominator. Why one lowest common denominator was never going to be enough, and what to do instead.
  3. Where the languages disagree. Division, rounding, null, and the empty string that Oracle thinks is nothing.
  4. The cost, then and now. Why it would have taken years, and why that reason is mostly gone.

David Brandt is a computer scientist, systems architect and independent scholar based in Reykjavík.