Learning how to program effectively will eventually require that you learn more than just one language. You already know that there are different types of languages and different levels. There’s another fundamental difference between some languages such as between C++ and C#. Some languages are interpreted and some are compiled. And some like C# get compiled twice with some aspects of being interpreted too. Knowing how your code behaves will allow you to select the best tool for the job.
This episode builds on the turn left or right, jump, and take steps game by comparing different approaches that you could take and then showing how one approach leads to an interpreted solution while the other leads to a compiled solution.
It seems like compiling is the better option until you learn how flexible the interpreted solution can be.
So are languages interpreted or compiled? They can be either and sometimes evolve from one to the other. Knowing how your programming language currently behaves and what to expect from it in the future are critical to building a successful application. Listen to the full episode or read the full transcript below.
Let’s start by going back to the game described in episode 4. You’re playing a game with a friend and you can give your friend 4 simple instructions to turn left or right, jump, and take from 0 to 5 steps. Your friend has a starting point and will follow your instructions exactly to reach a destination. The one catch here is that your friend wants these instructions in the form of numbers where 0 means turn left, 1 means to turn right, 2 means to jump, and 3 means to take steps. The number of steps to take follows the 3. So a 3 followed by another 3 is a valid sequence and means to take 3 steps.
There wouldn’t be much of a challenge to this game if you could just follow behind your friend and figure out what direction to go as needed. You might as well just walk directly to the destination.
So to make things more interesting, you’ll need to plan the instructions you can give to your friend ahead of time because once the game begins, you can’t change them.
This series of instructions becomes your source code.
Now you want to work with your source code in terms you can understand. But your friend wants the instructions as a series of numbers. You have a lot of planning to do and working with numbers directly would lead to too many mistakes.
So you’re going to need something that will turn your source code into the numbers that your friend expects.
One way to do this would be to write your source code in your own terms and then follow your friend and translate each instruction to numbers as needed. This will meet the rules of the game because you’re not changing your instructions, just translating them as needed. In other words, you’re interpreting your instructions. You’ll be a bit slow to navigate because your friend will need to pause after each instruction while you translate the next source code instruction.
Another way would be for you to translate all of your instructions once before the game begins. You’ll be more prepared this time because you compiled everything. The benefit is that you can navigate faster because you’ll have each instruction already translated and ready as soon as it’s needed. You won’t have your source code anymore with you during the race. Just your series of numbers that you compiled.
If this was a race between two teams that have both written their source code before the race begins and one team took the interpreted approach while another took a compiled approach but waited until the race begins to start compiling, then they would probably end up at the destination at the same time. But that’s only because the compiling was done as part of the race. That’s not the way things work. When you compile your source code, you have the opportunity to do this work once before the race even begins. It’s a bit like cheating but the rules allow it. You have a huge advantage over the team that is interpreting the instructions during the race.
There’s got to be a downside to compiling your source code ahead of time though, right? I mean, if there was no downside, then why would we even be discussing interpreting vs. compiling?
Let’s say both teams show up for the race as usual and one team has the source code ready and will be interpreting it while your team has taken the time to compile your source code ahead of time. But before the race can begin, your friend gets sick and you bring in a different friend as a substitute. Should be fine right? You’re not breaking any rules. You have your compiled set of instructions and are all ready. Only you realize too late that the substitute expects a different set of numbers for each of your instructions. Disaster! You start issuing a 0 to turn left and the substitute turns right instead. It’s too late to change it and you couldn’t change it even if you wanted to because you don’t have your source code with you. Your team loses. Had you been interpreting the source code instead, then you could have adapted to the situation and issued the numbers that matched what your replacement expects and at least tied with the other team.
What did we learn from this example?
The first thing to note is that the solution to this simple game could be either interpreted or compiled. And you could probably come up with a solution that uses a combination of both approaches. This means that almost any if not all languages have the potential to be implemented with either interpreters or compilers. There’s nothing in our simple language rules of turning left or right, jumping, or stepping that implies or requires this to be interpreted or compiled.
But there’s another aspect of this that I want to call out. Because technology constantly changes, it’s possible that decisions you make early in a project will no longer be the best by the time you complete a project. Staying up-to-date is critical but you should also pay attention to where things are going. You can use this to your advantage by selecting a path that initially may not offer the best of what you’re looking for. If you’re right and things change to your advantage, then you can jump ahead of the game. If not, well, hey, it’s software. Just wait a bit and it will change.
Languages like C++ are compiled and that gives them tremendous speed. But C++ gets compiled to a specific platform. Sort of like how we compiled our game to the numbers our friend expected. An Intel processor is like this friend and expects certain number values to mean specific things. Try moving that same compiled set of instructions to an Arduino with an ATMEL micro controller and it will likely crash on the very first instruction.
Since PCs running Windows and Macs running OS X are both using Intel processors these days, does that mean that a compiled C++ program can run on both? They both have the same processor that expects the same number values for instructions. Sadly, no. You can’t do this. But not because of the processor. When you build a C++ application, you’re not just compiling your source code for a particular processor. You’ll also usually want to make use of features specific to the operating system. But even if you don’t do this, just the fact that you want your program to be loaded and run by the operating system means that your development environment will add code to your application that can only work with your target operating system.
Now what about C#? I mentioned that it gets compiled twice and has some aspects of being interpreted too. This at first seems like it would be completely unnecessary. I can tell you that the C# language designers are some really smart people and have some good reasons for this. We’ll explore this multi-step process more in the next episode.