Brooks's Blog

Interpreted & Compiled Languages

Oct 14th, 2023

For longer than I'd like to admit, I didn't know the differences between an interpreted (AKA scripting) language and a compiled language. I always knew there were differences, but I never fully grasped them. Now that my understanding of the two is much stronger, I'm willing to help others understand!

As a disclaimer, the terms "interpreted" and "compiled" only exist at a semantic level. Any programming language can be interpreted or compiled (that is, if the appropriate tools exist). What ends up defining whether a language is interpreted or compiled is:

  1. A language's strengths/weaknesses.
  2. The community's use of a language.

I'll use Python as an example. Python is mainly translated into intermediate code (explained later). Then, the code gets interpreted. However, Python may also be compiled by using tools like Cython if it makes sense for the context in which it's used. If compiled Python development were to become more popular than interpreted development, it's likely the Python community would describe Python as a compiled language rather than an interpreted one.

I'll discuss both language types simultaneously, starting with how they differ in the execution process.

Let's begin with interpreted languages. An interpreted language (JavaScript, PHP, and so on) requires source code to be accessible at runtime. This human-written code is translated into machine code. Then, it's immediately executed line by line. Execution begins at the top of the source code. In this context, the source code is referred to as a script. The interpreter works down the script until there is nothing left to interpret and execute.

A compiled language (C, C++, and so on) takes source code and runs it through a compiler. The compiler's job is to translate human-written code straight into machine code. The result is an executable file that is readable by the computer's Central Processing Unit (CPU). Running the executable file will execute the code.

It's worth noting that sometimes both interpreted and compiled languages will get translated into what's called intermediate code. Intermediate code is simply a bridge or a "halfway" point between human-written code and machine code. Mozilla's Spidermonkey engine, used to power Firefox, makes use of intermediate code to shorten execution time.

Back to the topic at hand.

Executable files are platform-specific. An executable file in a Windows environment will not work in a macOS environment without some tweaking. This means compiled languages are restricted to the environment they can execute within. Thus, making them less portable than interpreted languages.

On the other hand, interpreted languages are considered to be more portable. Most interpreters are created with various operating systems and hardware architecture in mind. This allows interpreted languages to be run in a multitude of computer environments. For example, JavaScript is the language that dominates the web. Web browsers contain interpreters to run JavaScript. So long as a computer user has access to a web browser, they can execute JavaScript code. Spidermonkey contains an interpreter, as well as Google's V8 JavaScript engine that powers Google Chrome.

If these were the only differences, there wouldn't be an argument to work with compiled code (outside of maintaining legacy codebases that use compiled languages). However, this isn't where the differences end!

Compiled languages undoubtedly execute quicker than interpreted languages. Simply put, compiled languages translate to machine code before runtime. Thus, there is less to do during runtime. Assuming there is time to compile the code before running it, compiled languages will generally be faster than interpreted languages.

Unfortunately, interpreted languages lack the speed that compiled languages gain from translating source code to machine code before runtime. Though interpreted languages are generally slower during execution, it doesn't necessarily mean these languages are worse off because of the added translation step during runtime.

Interpreted languages report errors in terms of the source code. This makes debugging easier compared to compiled languages. Also, the developer doesn't have to wait for code to compile only to find bugs that need to be addressed. The developer can run code quickly over and over again until they are finished debugging.

Compiled languages generally aren't as easy to debug. They compile the code and then run the code. Because of this, the developer doesn't have the same visibility into the program's behavior compared to interpreted languages.

Compiled languages may not be as easy to debug. However, they are generally considered more secure. Compiled languages require machine code at runtime. This is great for security. As it turns out, most people aren't very good at programming machine code! This complexity adds additional security to compiled codebases.

Due to source code being required at runtime for interpreted languages, they are much easier to modify if someone with malicious intentions is able to get their hands on the code. In modern codebases, this is less of an issue. That being said, it's still something to keep in mind for those coding in interpreted languages.

At this point, I've covered most of the differences between the two types of programming languages. Like most things in life, one of these types isn't inherently better than the other. They both have contexts where they work the best.

I've mainly used interpreted languages for the work that I've found myself in. That being said, I'd love to get more experience with compiled languages in the future!