When we write a program, we're just taking the algorithm that we want to use and expressing it in a way that the computer can understand. This is really what programming is all about. So, a program is just a way of manipulating data, i.e, running an algorithm on some data. In the von Neumann architecture, that data is stored in memory at some address. In the old days of programming, programmers had to know the exact location of where data was stored. Here's a photo of two women programming in ENIAC, which was one of the first computers. When I say that the programmers had to know where the data was stored, I mean, they had to know physically where it was stored, so that they could connect the wires to the right places. Later on, in the 50s and 60s, as computers got smaller and smaller, programmers no longer needed to know where the data was physically stored in memory, but they still had to know the exact numeric memory address of where the data was stored. Here, we see some women using punchcards to write a program. These were little paper cards with holes in them that represented the instructions and data. For every instruction in the program, the programmer would have to punch some little holes into the card and make sure that she punched the right sequence of holes to specify the right numeric memory address. Think about how time-consuming that would be. Here's a photo of a mini-computer from the 1960s. As the name implies, it was a mini-computer. The programmer programmed it by flipping the switches on the front panel into the right sequence for a certain instruction to specify what it did and what data it used. Although they didn't have to physically put little holes into little pieces of paper, they still had to know the exact numeric memory address of any data they wanted to use in their program. Nowadays, computers are so complex and do so many things that it would not only be impossible for the programmer to know the actual numeric memory address of where a piece of data is stored, but impractical since it would restrict the computer from doing other things. So, now when we write a program, we can use meaningful names or labels for the addresses that represent what data is being stored there. These names or labels are referred to as variables. As an example, here's some Python code that looks at a collection of numbers and tells us how many of them are even. Don't worry about understanding this code just yet because we'll see it in the next part of the course. But important thing to note is that when we write a program, we use variables such as values and count, which refer to addresses in memory where data is stored. We don't have to actually know these numeric addresses. The computer figures them out for us when the program is running. The analogy I like to use is the Empire State Building. The Empire State Building's actual address is 350 Fifth Avenue. But no one asks a taxi driver to go to 350 Fifth Avenue. You don't have to know the actual address, you just tell the taxi driver to go the Empire State Building, and they know the actual address. So, we can say that Empire State Building is a label that represents that address. So, let's go back to this Python example. Again, don't worry about the syntax of the code just yet because we'll spend a lot of time on it in the next part of the course. But we just want to show it as an example of using labels or variables to represent memory addresses in our program. The simplest variables are those that hold a single value such as a number or a letter. In this Python example, there is a variable called count, and at first, we want to give it the value zero. Because variables are just names or labels for addresses in memory, we can use them when we perform the basic memory operations which are reading and writing. For instance, when we want our program to write a value to a variable, this just means moving that value from the CPU to the right place in memory. In this case, the programmer attempts to set the variable count to zero. But before it's written to memory, the CPU translates the label count as the actual address, which here, we'll say is 1234. Now, this is the same as we saw in the previous lesson. The CPU then sends that address and data to memory, where the value is then written to the correct address even though the programmer didn't know what the actual address was. So, we can have a variable that refers to a single piece of data like a number or a letter but sometimes we want to group pieces of data together. Again, don't worry about understanding all of this code just yet, but you can see that aside from our variable called count, we have this other variable called values which holds a bunch of numbers. We'll refer to this as a collection. In many cases, the values in the collection are stored in contiguous memory addresses, one value after the next, as we see here. This makes it really easy to iterate over all the values one after the other since they're right next to each other. When we use these sorts of collections, we often want to access individual elements. In our programs, we can do so by using a subscript or what we call an index. That allows us to specify which element we want in the collection. Many programming languages uses zero-based index. So, what we think of as the first element is actually index number zero, and so on. Here, the number eight is at index number two, which we can write using these different styles of notation. So, we've seen how we can use a variable to hold a single value like a number, and how we can group values together in a collection and give that whole collection a name, and then use indices to refer to individual values or elements. But sometimes, we may want to group values together and give that grouping a name, but still have distinct names for each element. This is referred to as an object. Let's say we have a variable that represents a dog, and we'll name this variable Jake. But this variable is actually just the aggregation of two other variables, which are the dog's age and weight. The whole aggregation is considered the object, and we can refer to this entire aggregation using the object's name, which in this case is Jake. In this lesson, we looked at memory a little bit more and saw that most modern programming languages use what we call names or labels for addresses to make the code easier to write and understand. A label or variable can refer to a single value by the number or a letter, a collection of values, that can be accessed by their index or position or group of values that have their own individual names, which we call an object.