Compiled and Interpreted Languages

White server room with scattered server racks.

One of the things that is important to understand as we transition from Ruby to Rust is the difference between compiled and interpreted programming languages. Rust is one of the former and Ruby is one of the latter. To discern between the two, we have to go a bit back in time.

During the 1940s, we saw the event of electrically powered computers. With these computers, programmers worked with assembly language, which is a low level programming language that's supposed to communicate directly with a computer's hardware. This was at least a step up from programming in machine language, which is programming directly in binary or hexadecimal.

I don't know about you, but I don't particularly want to program right in binary or hex, and even assembly, which is machine code adjacent, also does not sound like a good time. After a while of doing this, people figured out that this was really hard and so the search started for a better way.

In came the interpreter. What an interpreter is, is a bit of software that sits between you and the computer. It takes the code that you've written, and then converts it into machine code for the computer to then immediately run. Which sounds great on paper, but a little less so in execution. The problem here is that we have to interpret this code every time we want to run it, and this makes it much, much slower.

We can contrast this approach to that of compiled code. Where we take the code that you've written and the compiler then translates that into machine code ONCE. We take that machine code and run it, and it will generally run faster because we've already translated it, and we no longer have to interpret it each time we wish to run the code.

Now this sounds great, right? We front load the work and now we have this compiled code and why wouldn't we just do this all of the time? In practice, things are a bit more complicated. When you compile code on a machine, you get what's called an executable for that machine. And the important part is the part where I said that it's for that machine. You can't just take an executable compiled on and for an ARM-based Mac and run it on an Intel-based Mac or some other platform. You need to make a separate executable.

When we're dealing with interpreters, you essentially download an interpreter literally for your type of computer, and now you can trust that it will successfully interpret and run any code you come across.

Long story short, both exist and are in wide use today. One is not better than the other. Much like most technologies that we use, it's all a big system of tradeoffs. One is generally better than the other in certain circumstances. Both come with advantages and disadvantages. If they didn't, then what would developers argue about?

Subscribe to Rust for Rubyists

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.