Last year, I did a course that I strongly recommend, From Nand To Tetris. I enjoyed it a lot. This course teaches how to build a whole computer from the logic gates to the Operating System. The course has a section in the middle to implement the compiler for a high-level programming language called Jack.
Today I want to explain a small part of the compiler that I found enlightening in understanding how objects, classes, and instances work. The details differ from one programming language to another, yet, they are highly similar at the low level.
Understanding how programming languages work at a low level will help you learn the next one faster.
Jack is the programming language used in the course. I won’t go into any details because I only care about two lines: creating an instance and calling a method.
let game = SquareGame.new(10, 400, 300); do game.run(5);
The first line is how the instances are created by calling the
new method; while the other line is very similar to how languages call methods:
game.run(5)—except for the
do in front.
We don’t need to go into the details of Jack constructors. Instead, I want to go into the details at the low level: What happens in the RAM when we call
SquareGames.new(10, 400, 300).
The RAM is like a library with shelves; the amount of data we can store in one is limited. Therefore, normally a shelf cannot hold a whole instance because an instance holds more than one piece of information.
game instance has three instance variables: ball radius (first argument), canvas width (second), and canvas height (third). Where do these values: 10, 400, and 300 live?
The answer is that each value lives on a separate memory shelf.
SquareGame.new(10, 400, 300); is called, behind the scenes, the compiler (or the OS) needs to find memory space for three consecutive slots.
When these spaces are found, the values are stored consecutively—one in slot 0, another in slot 1, and the last in 2. There is a part of the compiler (a symbol table) that keeps track of the indexes for each instance variable: “ballRadius” is slot 0; “width,” 1; and “height,” 2.
What is an instance?
What is the value of the variable
game then? Does it store 10? 300? Or 400? The answer is none of them. This is because the
game variable holds the address to the space of the first variable instance, which is also known as a pointer.
Storing an address in memory is an important idea in programming. The value of the instance is just a reference to a part in memory where the actual values are stored. This concept is essential in object-oriented programming languages like Python, Java, Ruby, or JS.
Where are the methods?
The obvious question now is, where are the methods?
The answer is actually simple; there is no such difference between method and function at the memory level. They are represented precisely the same way; they are just a location where the code needs to jump.
The difference is at the compiler level; the compiler does some magic to provide the functionality we expect from a method. Specifically, the compiler transforms:
game.run(10); // into run(game, 10);
Therefore, the main difference is that the object is the first actual argument that a method receives. This is how the method has access to it, not because of some class magic, but because the compiler passes the object to the function as an argument.
If you know Python, you are familiar with how methods access the object:
def run(self, time):. Now you understand where this originates.
What did we learn?
Classes, methods, and instances are just high-level concepts for developers to write more maintainable code. They do not add any new features at the machine level; nothing new can be done in Python that we couldn’t do in C or Assembly.
All high-level programming languages are similar at the low level. Therefore, learning how this works puts you better positioned to learn new languages and go deeper into other advanced concepts such as inheritance and concurrency.
If you like this post, consider sharing it with your friends on twitter or forwarding this email to them 🙈
Don't hesitate to reach out to me if you have any questions or see an error. I highly appreciate it.
And thanks to Michal and Sebastià for reviewing this article 🙏
Thanks for reading, don't be a stranger 👋
GIMTEC is the newsletter I wish I had earlier in my software engineering career.
Every other Wednesday, I share an article on a topic that you won't learn at work.
Join more than 3,000 subscribers below.