What’s a Transpiler Anyway: Language Levels in Plain English

Máté Safranka
6 min readJan 29, 2019

--

If you’re just getting into programming, or work with developers as a non-tech professional, you probably hear a lot of terms people just assume you know. In this series, I attempt to explain those fundamental concepts.

Compiler. Transpiler. Interpreter. Runtime. JIT. AOT. These are just some of the words you’ll hear developers throw around as casually as the days of the week. As a newcomer, one of the most intimidating things about development is the most fundamental one: how does our code even work?

Well, if you’ve read my Rest API article </subtle-plug>, then you know I like to start with the basics.

Machine Code

It’s safe to bet that anyone who has ever come in contact with a computer has at some point heard the phrase “ones and zeroes”. Supposedly, this is what everything comes down to, from the holes on ancient punchcards to the signals blasting through fiber optic cables. So what exactly does it mean?

At their core, computers are of course electronic. Every chip in your device contains millions of circuits, which can be in precisely two states, i.e. they either have a current running through them, or they don’t. In extremely broad strokes, this is what those ones and zeroes represent: whether a certain circuit at a certain time should have a current. Computer Engineers, don’t @ me.

What this means is that, in order for the computer to do anything, we have to power the right circuits. This code, which affects the hardware at its physical level, is what we refer to as machine code, native code, or just binary. In the earliest days of computing (and I mean 1940’s early), this is what programming was.

Needless to say, it had a long way to go.

Assembly

The biggest challenge with writing machine code was that you had to be intimately familiar with the actual wiring of the computer you worked on. This wasn’t all that bad when there were about five computers in existence; once they became a commercial product, things quickly started to get out of hand.

As individual manufacturers started producing their own hardware, naturally they wanted to stand out from the competition by adding unique features. It became apparent that knowing the actual circuitry of each model was not an option. However, even though each computer was different, there were some very clear similarities in their overall designs — or, as they came to be called, their architectures.

Programmers realized that computers built along the same architecture could be programmed more or less the same way. This gave rise to the first generation of abstract programming languages, assembly. Instead of direct hardware instructions, it described operations such as “write to memory”, “add two numbers” or “compare values”. As trivial as these sound today, at the time they were a godsend to developers everywhere.

Machine code (middle column) vs assembly code (rightmost column) for adding two complex numbers. (Wikimedia Commons)

(And, if you’ve been following along, then you can also recognize that assembly was perhaps the very first abstraction layer.)

One important thing to know about assembly is that it’s not one language. Rather, it’s a term used to describe any instruction set that can be directly translated into machine code for a certain architecture; meaning that each architecture has its own assembly.

Compilers

As programs grew in complexity, from simple calculations to sophisticated data processing, so grew developers’ need for an even more unified and expressive language. After all, different architectures may have had their own quirks, but at the end of the day, they could all perform basic arithmetic and memory operations. And while assembly was at least somewhat human-readable as opposed to the random numbers of machine code, even a short mathematical formula would have to be written as dozens of lines of code.

The breakthrough came when developers realized that, as long as this hypothetical unified programming language was formalized clearly enough, they could write programs which would take a string of text written in that language, and translate it into that architecture’s assembly code. These “translator” programs became what we now call compilers, and they paved the way for some of the most enduringly popular programming languages. The most famous ones are C, and its later improved versions C++ and C#.

C code, demonstrating its many advanced (compared to assembly) features such as code structuring, functions, and importing. (Wikimedia commons)

Interpreters

The difference between a compiler and an interpreter is sort of like the real life difference between a translator and… well, an interpreter.

  • A translator takes a book written in a certain language and creates a new book in a different language. The process is usually done in multiple revisions, and therefore takes more time, but the result has the potential to read as though it had been written in the target language to begin with.
  • An interpreter, on the other hand, will stand next to a speaker and translate their words on the fly. Since there is no chance to review or polish the translation, it will never sound quite as fluent; however, the process itself is much more flexible, and provides immediate results.

On a similar principle, a compiler will run once and create a self-contained executable program that can be run at any time, while an interpreter needs to run in parallel to the code it’s interpreting. Generally, compiled code is used for software that needs to be installed permanently, whereas interpreters are used for programs that are to be executed and then discarded. Such programs are also often referred to as scripts.

As you may already guess from that term, arguably the most important such language today is JavaScript. Your browser has a built-in JavaScript interpreter that runs constantly in the background, executing the code for each website you visit, and then discarding it once you navigate away.

(Just to keep life simple, though, the Electron framework can compile JavaScript into native code, while Progressive Web Apps allow us to create installable software that runs on interpreted code, so there is that.)

Miscellaneous Terms and Nuances

High level vs low level languages. The level of a language doesn’t refer to its complexity or sophistication, but rather how far removed it is from the hardware:

Thus, compiled languages are generally considered lower level languages, while interpreted languages are higher level.

JIT vs AOT. As they gained popularity, more and more software was written in interpreted languages. Some of this code was meant to be executed extensively, which created a need for better performance. To achieve this, certain interpreters also started acting as partial compilers. They try to detect which parts of the code are the most frequently used, and they’ll temporarily compile those parts into native code to make it run faster. This process is referred to as run-time compilation or JIT (Just-In-Time) compilation. The term is contrasted with AOT (Ahead-Of-Time), which refers to traditionally compiled code.

Transpiler. As opposed to a compiler, which translates higher-level code into lower-level code, a transpiler translates one high-level language into a different high-level language. Transpilers are most common in web development, where they are used to convert enhanced versions of JavaScript (such as TypeScript or JSX) into “vanilla” JavaScript that browsers can execute.

Hopefully I have managed to give you a general idea about the various forms of code execution. Allow me to close off with a popular developer joke that can also serve to check if you’ve grasped the basic concepts:

Q: How can you tell the difference between a Computer Scientist and a Computer Engineer?

A: The scientist will start a sentence with “In low-level languages such as C++…” while the engineer will start with “In high-level languages such as C++…”

Mate Safranka is a frontend developer at Supercharge. If you liked what you read here, you might also be interested in his other articles about Rest APIs or HTTP and WebSockets.

--

--

Máté Safranka

Frontend developer, learning confectioner, hobbyist game maker, amateur writer.