 Good Monday afternoon. Hello. All right. Welcome Monday. Midterm thoughts. We're going to go brief. Thumbs up, thumbs down. I don't know what that means, but, you know, wait, you can express yourself. You can do middle. I didn't have to start late. I appreciate you being flexible with that. Sometimes weird winter things happen, but that happened to me the first time I did midterm. So I was literally running with a box of midterms to the glass. It was super fun. All right. Let's see. Project 3 due on Friday. Let's get started on the next topic. Any other questions or anything? When they're downgraded. Before the next midterm, we'll say that. That's a great question. You've got to remember, there's 238 of you and six problems. It creates a lot of stuff to be graded, right? And I like to have each problem graded by one person, right? That way you're consistently graded on every problem. So that requires us handing things off to each other. It'll take a little while, but as soon as we have the results, you will have the results. Any other questions? Let's get back to semantics. All right. So we've talked about variable resolution and how the compiler is able to map a variable usage to the variable's declaration. And we also know a little bit about scope so we can understand how long a variable's declaration is valid for. Now we're going to talk about function resolution, right? So we talked about, so what are some of the different ways on Wednesday that we talked about how functions can be, how we can know how to refer to a declaration of a function from its usage. What are some of the ways and some of the variables that we're going to say to these? How do I see map a function, an invocation of a function to its declaration? By name. By name. Yeah, so it only looks at the name, right? It doesn't matter. You cannot define another function with the same name no matter if it has different parameters. What about C++ or Java? Usually name and parameters, sometimes we can parameter types, right? So you have the name, the number of parameters, and the title of parameters, right? And so we went to all this and we saw this and we saw that another way of looking at disambiguation rules is using the function signature, right? So these are two sides of the same coin, right? So disambiguation rule says when we invoke a function how do we know which function we're actually calling? A function signature says what is the signature of a function? So I see the signature of a function is just the name, right? Because that's all the information you need to know to know which function gets called. Whereas in languages where you have parameter number and parameter types, the function signature has all those things. Okay, we saw this. So in C, function signatures are name only, which can be incredibly limited. Whereas in C++ function signatures are names and parameter types. So you can say that the function signature for C++ function is some name followed by the types of the parameters. Cool. All right, so let's walk through an example of using C++ but also using the C library functions to be super confusing. So we're going to include standard IO.h. We're going to call a function foo that... So what is the type of foo? So what's the function signature of foo? So we're in C++. So what's the signature of foo? foo, gotta have foo, why? The name. The name, right? Part of the signature is the name. And foo, right? Or nothing, no parameter list. Why don't we include int? Because the return type in C++, the return type doesn't mean anything in response to the function signature. And deciding between resolving a function. And so we don't care about that. We don't include that. And now you can find another function foo which takes in an integer this time, returns an integer, and this returns 10 plus x. So it'll be a function signature for this function. foo int, is it going to be foo int x? What do you think? Why not foo int x? So at least from deciding which function to call in C++ the only thing that matters is the name of the function and the types of the parameters in the order. The name of these parameters doesn't matter at all. We can't make a new function foo that takes in an integer called bar and expect that to be a different function. And part of that is in C++ do you have a way of invoking a function and saying this specific parameter is this value? No, right? We have no way to say that. We only invoke a function and we pass parameters to it and those parameters have types and those types get mapped to the invocation. Cool. So in my function main I can call foo and set it to return value equal to whatever test parameter I want. And when the compiler is compiling this, remember all it sees is the ID. It just sees the ID, the string foo and then that's to say which function foo gets invoked. So here it says, okay, I know I have foo with zero parameters. Do I have a function defined as foo with zero parameters? Yes, I looked up in my symbol table just as we saw before. Now once again this is different from static dynamic scoping in that you can do function resolution differently and also have different types of static and dynamic scoping. But here in C++ we're assuming static scoping, we're mapping this instance of foo, this invocation of foo to this definition of foo. And the same thing here with bar. Now we can pass test. So what's the type of the argument test in? So then what's the type of foo here? So what function is going to be invoked here? foo that takes in one parameter and that's an int. And so that's what the compiler tries to map this invocation of foo to. And so it says, oh here there's a function called foo that takes in an integer. Great. We can compile this program and it's going to output 10 and 20, which is exactly what we think it should. Questions on this? But this is just another knob that the language designer can tune and change. They can say functions have to be unique by name. Or they can say they have to be unique by maybe just number of parameters. Or they can say they have to be unique by name, number of parameters, and type. And so this changes the way we program this language and this changes the exact semantics of what it means when you see a function invocation here. How do you map that invocation of that function to the actual function like it's called? Cool. All right. Moving on. Now we get to assignment semantics. This is where we're going to be super duper ultra precise, which I guess is a very not, probably, ironic way of saying precise, very precise. So the question is, what exactly happens in the following statement x equals y? What was that first comment? Depends on the language. Depends on the language? Why? Yeah, so part of it, so our intuition is we're copying what, the value of y to x. Right? But really it depends, and so we need to be very precise in saying what do we actually mean. So we need to define four concepts here that are going to help us to talk about the exact semantics here. Because there's the name x, there's a variable hopefully called x that's been declared in our program. There's also a variable that's been declared called y. Assuming this is a valid statement, these are both in-scope variables, which means we can map them to some declaration. They have names. And so names as we saw is why we went through that whole process of scoping rules. How do we map this name to a declaration? Next we want to talk about locations. So what would be the difference between a name and a location? Anything about where x is stored or what happens to x? Right, x is a way for us to abstractly think about and define a variable. Right? The computer can do whatever it wants to x, but it has to put x somewhere. Right? x must be somewhere in order for the computer to reference it and change it. We don't actually care when we're programming. Is that a true statement? Most times we don't care exactly where the compiler is putting x. The compiler could put it in memory. It could store it to the disk. It could pass it on to another computer to store for it and retrieve that value from that other computer anytime it needs it. It could optimize in a way to register on the CPU. Do you care? What do you care about as a programmer? What do you care about? It's available. If I want to do something with x, make sure that I get it. Exactly. When we modify or change x, when we use it later, we want to see those modifications change. One step further. When we set it to something they can be expected to still be that something when we come back for it later. We want to be able to do a variable. Set it to a new value. When we access or use that again, we better have the same value. It better not have changed in the meantime. Unless we wanted to do that. Which is a whole other issue. Using shared memory or something like that. But frankly, when we're just talking about learning, we don't care where the computer puts this. But we know it has to put it somewhere. We're going to use location for this. We're going to say a location is a container that can hold a value. That's it. We're going to talk a little bit more abstractly. We're not going to think about exactly where containers can hold values and all that kind of stuff. We're not going to care where it is. We just know that the computer needs to have this value somewhere. We need some way of linking those two things. Right? We know we have a name. We know that the computer stores the value that we associate when we assign to that name somewhere in I guess I'll be stupid, in the computer right? It's storing it somewhere. But we know in some abstract location and we need some way to bind and say that this name now refers to this location. This name is bound to this location. And finally we have the things that we're putting into locations. Right? We have some kind of value. We're actually kind of constrained in certain languages between what values we can express. Right? So we have an integer in C on a normal 32-bit system. Can that represent all possible integers? Why not? That seems really annoying. When you write an algorithm at a high level do you really want to care about you just want to say I want a number. That number could be zero to whatever large number I think of, right? So why do we care? Why does it actually have six set of values? There's a lot of integers. Yeah, I mean that's part of it, right? Why else? Well, it's tight. Care about it's tight? Why? Well, it needs to be an integer because you're going to be performing operations specific to that type. True. Let's say you're trying to find an integer class as a capital I full word integer that represents all possible integer values. And let's not even worry about negatives we can always deal with that. Like zero and up. Why can't we do that? Why don't most languages allow us to do that? We're going to make it very, very easier or harder to overflow. I'm trying to represent all numbers. But I care about it as well. We might not require that big number limit. For normal operations use that. If you really want to use large number, large integer then use the type for that. Okay. So I only want to use so I may only want to store a fixed number. Like for instance, if I was storing dates and I just wanted to store the last two digits of a date. Right? Which is the Y2K bug. But I want to be super clever to store those last two digits. But still, what's the fundamental reason? Why is that a benefit to me to be able to to say my range and set of values is fixed? I'm going to say space. What was that? Say space. I got 8 gates of memory in this thing. I don't know, I'm convincing, I think it's difficult. So you can tell the difference between the types. You can tell the difference between the types. I always store like a type bit or more than a bit. Because types, I mean we'll go over and talk about types later. But I get to say that I even find a new type that says like a centimeter is also an integer. Right? That's a different type. And I'd say that centimeters and integers are not the same thing. To find a new type, inch for an inch is also an integer underneath but inches and centimeters are definitely not the same thing. What you're getting at, but I don't think any of the software that I've ever written is going to count higher count to a higher integer than can be stored in 32 bits. You could probably find some specific applications but generally, kind of like we talked about that for the most part you don't need to count that type. You do write a library so you can take the numbers you can store and use them to represent bigger numbers. So why 32? Why do we care about 32 bits? The numbers. Because why? Because it's in the hardware. It's in the hardware how? And you say that like a 32 bit of 40 or 64 bit hardware. Yeah, so it's usually a couple ways to look at it. Some ways could be registers. Fundamentally, the CPU that you're executing on has limitations on what it can do. So modern, let's say 32 bit CPU has registers that store 32 bits each and has operations to calculate and do addition and subtraction and it's on 32 bit like integers. But you're not coding through a specific machine and you code C or C++ if you're coding this you can go to any language. So why? Why do we still care? Well, you said that we're trying to write a general purpose solution that'll work with everything for a solution that only works with 32 bit machines then it certainly wouldn't work with a vice versa. Okay, cool. I'll take a flip side of that to say backwards compatibility would be one reason. So A, C was written in the 70s as like a high level assembly language to write the UNIX operating system in and at that time they had limitations on sizes so they sensed to continue that limitations into a high level language. Actually, a lot of languages came from C. So languages like Java which are made much afterwards and why would it matter to a Java program if you have 32 bit integers underneath? But they still carry the same restriction I don't know, maybe it's because they felt people would be more used to that it'd be easier to bring that previous knowledge into the new programming language and you'd get started and not have to use this concept. Something that should be performed it doesn't mean by performance or maybe I just injected that into that conversation. So it kind of all linked. So why? I guess the question is, so we just said the 32 bit CPU only operates on 32 bit numbers does that mean we have to always use 32 bit numbers? Can we do 64 bit addition on a 32 bit CPU? What's the difference? It was two cycles two memory cycles. Yeah, it's going to require multiple clock cycles in order to essentially emulate a 64 bit operation on a 32 bit and more registers. So now we're getting back to the talking about size. Size of things. It really is I think a lot of it comes back to performance. When you write a C program and you declare an int you know that that's going to be whatever the default size of the system is usually let's say 32 bits it's going to be 32 bits on the CPU. Now if you start to try to change that and try to when you start doing 64 bit or 128 bit math or whatever on a smaller processor you have to do a lot more processing in order to get that to work. So we're kind of if you think about it as a community we've kind of made this implicit tradeoff that says I want to use super performance. I want to have really good efficiency and performance and if I need that flexibility like somebody said I can use a library. If I want to represent there's a big number of libraries in most languages that will handle any large number you throw at them. But their calculations are slower. Anyways this is getting thinking about values so that a value that we're talking about on a program and a computer is fixed. And this comes from physical limitations really. Before you move on we can talk about floating point precision and how when you're doing linear algebra the number of decimal places back first you have plays a big role in the conditioning of your linear system you have crappy conditioning in not enough decimal places and your rocket's going to explode wherever it's traveling to. Yeah so we need to and that's a kind of a side step that question. We didn't talk about floating point at all because you're using floats and they should use doubles and all that kind of stuff and depending on how many calculations you do you need to be very aware about how your errors accumulate as you're doing these linear systems and all these equations. There's actually a whole area of scientific computing and that is like trying to deal with this problem and said not only can we view algorithms that are super fast that a computer can do but how can I minimize this error propagation so yeah there's something to think about right? Float's the same way. Float you need to represent usually 32 bits you're trying to represent an exponential decimal number in 32 bits which is hard and double is usually larger 64 but CVUs usually have built-in support for those types of things and they even have built-in support now for doing operations on large arrays of numbers they have different extensions and you do need to worry about it unfortunately I haven't reached that stage yet where you can just code in this super high level I don't care about the machine mentality because often times they can come to bite you if you're in a certain domain and using certain types of stuff I use famous examples in a lot of video games where weird things like being able to slip through cracks in balls and stuff are due to bugs and floating point calculations because the things didn't line up exactly right so there's like a little hole in the wall and you can kind of get through something because that's where usually those problems come from alright so how do these four things join all the way back to the Simon's Mantis if you're getting super low into the details of the CVUs how do these four things come together the names, location a binding between the names and location and some kind of value so we're going to use super awesome diagrams I guess I should say another side benefit that we're going to learn here in this section and we go over like midterm from what was it, fall 2015 that example midterm I sent out maybe you got to a question with like a bunch of crazy pointer arithmetic maybe you saw it yes that's what this, so I'm going to teach you about a tool we're going to talk about box circle diagrams you will become a pointer god and goddess witch, wizard, I don't know what's your favorite like ultra powerful thing that will be you with pointers you'll be able to deal with address of operators complicated triple quadruple dereferences and be able to know exactly what the program does so that you can never write that in your code but you can understand what these things do and when the compiler tells you oh the type doesn't match you need to dereference something you're not just like okay just add an ampersand and never think about it again understand what's going on and why the compiler is yelling at you so we can get a super powerful section actually without this section so we're going to represent we have a decoration of an integer x so we have a name, the binding location, the value so we declare an integer x what are we telling the compiler to do for us let's take c for now what are we doing yeah so we're first saying that we want to name something we have a name x that later on in the program when you see an x all references to x that results in the same decoration mean the same thing so we have a name x and we're asking the computer to give us some location to put x in and bind those two the name and the location are we telling anything the compiler hanging on the value here no but are we telling it what the possible range of values can be yes we're making an explicit thing here if we had a character named x that would only be able to represent 256 values because it's an 8-bit integer we use enums we're doing the same thing the token type enum in project 2 defines a set of values so that way we declare a variable that's of a token type the compiler can check and make sure you're only using elements from these values this fixed set of values box circle diagrams they're literally just like the name implies going to have boxes and circles so the name is going to be x the location is going to be a box the binding and a line it'll be a line between the name and the location and this says that the name x is bound to this location does this location have a name maybe we'll get to that depends most times yes most prior languages give us a way to talk about a location the address of operator the memory address that is associated with a location in some languages like java we can't get that we don't know where things are stored we can't get the memory address of anything in java and yet we can apply these same concepts to java we have the name a binding a location and finally the value is going to be a circle inside the box so there we go right now the value inside this location so now I'm going to try to access and print out x what's going to be printed out close up anything that's in that range could be printed out because I did not tell the compiler exactly what I wanted inside the value of this location that's associated with x so this is the way we'll talk about this as we'll talk about what I'm going to say binding so we'll usually say x is bound to this location or we'll say the location associated with x will be another way to talk about this location right and so that is the box that x is bound to so this part is the easy part it's creating, when you see a declaration you know you can create a box circle diagram like this for x now we say x equals 5 what happens to our box circle diagram the circle has a 5 in it but what is the exact semantics that this means x is the name what was that sorry update the value of x to the value of 5 yeah update but x doesn't have a value x is just a name it's more than value 5 of the location yeah very close we want to copy the value 5 to the location associated with the name x so what's the difference between this and when we said x equals y earlier we copied the value y to the location associated with the name x what's the difference what's the difference between 5 and y 5 is direct and it's sitting in directly while the other one is sitting it's getting the value of what that is it's getting the value directly yeah but what's the difference between y and 5 5 is a literal 5 is a value itself but if you do an assembly it's immediate parameter yeah we won't worry about that but a high level 5 is a value whereas y is a name that has a location associated with it so we'll get into there's just like a preview where it gets deep into that and so how does this change our diagram we put 5 where like here in the circle yes super easy oh not there okay I was like I don't know what this is going okay so copy the value 5 to the location associated with the name x that is the precise semantic definition of what we're talking about here for our assignment so now if I have in x and in y and I say x equals y what are the precise semantics here yes since the value of x the value what is located in the address of y yes very close okay so using our super precise we're going to say copy the value in the location associated with y right so remember location associated with y we have y bound to a location that is the location associated with y copy the value in that location associated with y to the location associated with x x we have y we have something in there we're going to copy the value over here so then maybe this can give us some insight why can't I do 5 equals y 5 does not have a location right 5 is a value 5 does not have a location think we'll look at it later there's operators that will give us a location if we give it an integer like 5 but we can't say 5 equals y or 5 equals x yeah so if we go back here you're saying so is 5 stored in the memory so let's think about this for a second it's a good question so you're thinking about right in between these two lines in between x and in between x equals 5 right does 5 exist somewhere in the program where the program is memory well think about the process as an address space so let me give you a guess right now as to why earlier you said a value is an element from a set so it stands to reason that 5 belongs to a set that is defined somewhere to the system interesting so I have 32 bits in an integer because I mean every single number like we represented with 32 bits so from 0 to 2 to 32 is in my memory space because that's one element out of all that set I would think probably not right because then you have to have 2 to the 32 memory just to run one program right 32 times 32 because you need a place to put each of those 2 to the 32 integers then you run into a problem because with 32 bits of memory you can only usually address 2 to the 32 memory locations for memory addresses so your memory can only be 2 to the 32 that's why on 32 bit systems you have 4 gates usually so no it didn't get stuck anywhere or it hasn't yet maybe or maybe not probably there's a high probability that it's in there somewhere let's think about it this way I like that so if we just serve through the memory is there randomly some memory that happens to be can somebody file it 0101 0101 yeah so like a bunch of zeros and then 101 right is that likely to exist somewhere in our memory space maybe so I guess a better way of phrasing the question is if we change this 5 to a 10 does that memory location somewhere in the program now become instead of a 5 or 10 it should fly right so this code is going to compile down to C right and then or not compile down to C sorry compile down to like x86 assembly it's going to load the memory in x86 assembly a lot of times in the instruction this will be like a move a constant 5 into some register and then move that register into a memory location that would usually be how this would happen but does it have to be there I guess is a better question or I guess the root of what we're trying to add here does this line mean that 5 has to exist somewhere do you as a programmer in C care if 5 exists before this point what do you care about after this line executes right so if you were to access 5 and print out x sorry if you were to access x to print out x after this line you better see the value 5 so that's really the compiler's contract to you based on the semantics of this program right so so could the compiler compile it so it moves 5 into a register and moves it into a memory address that's associated with x yes could the compiler also put 0 in a register and increment that register 5 times until it knows that value 5 is there and then move that value into memory sure maybe it knows that on a certain processor that's actually faster than loading a value from an instruction those kinds of things happen right and compiler compilers have to be very clever in how they do these optimization tricks but the whole point is they preserve that contract with you the programmer that before this line you don't care what's in x afterwards it better be 5 and you don't care where that 5 came from you should know that x better have that 5 right so you don't really care where this came from that's a cool question okay so then how the heck do we get there what we're talking about before that 5 equals x that would be pointless because the left hand side if you overwrite that register it doesn't matter because you're never going to access it again think about how crazy that would be it's like I guess maybe you could make a language like that where you took 5 so you kind of took the thing of all the constants in the program are like fixed in this table like we were talking about like 0 or 2 or 32 and then you could assign to 5 and change its value to be something else like 0 and then later when people all try to copy 5 to somewhere else they get a different value you could compare these three things up I don't know why you never want to program like that but you could probably do it it would be easier just if you ever encountered a non-variable left hand side to reverse the assignment in case somebody's like dyslexic and they type it out backwards and the compiler just makes up for it it would work until you had variables one set to the other right, yeah, it's tricky the other thing is if you do like x plus y equals 10 on the left hand side you do x plus y what does x plus y look like a value, right, a number a value but you can't assign to that that'd be funny, x plus y is equal to x plus y I mean you can do what you want if you're creating a language this isn't going to be better to program probably not, I'm really thinking about it okay, cool so that's part of what it shows you is these semantics, right this is exactly what we mean when we see this line we say copy the value in the location associated with y to the location associated with x super annoying that the equals is assignment and double equals is equality I know you probably reached that point where you're very comfortable with that remember your first time doing that there are two completely different concepts one is a question asking are these two things equal and the other is saying hey from here on out assign this thing to this other thing and change its value forever there are two very distinct concepts that are separated by one equal sign so some languages actually have them distinct some languages have colon equals to mean assignment and like double equals to mean equality which gives it a little bit more separation but now we can evolve grown to the point where this is just how it is try to do it in a different language whatever okay, cool so now we can see things like this x is equal to x so this means copy the value in the location associated with x to the location associated with x this is exactly what we want to have happen right, so we have an x that's some value in it and we're going to copy it back to itself okay, so assignment semantics this is what we kind of hinted at when we talked about values versus like something of a location like why can't you have an x a 5 on the left hand side why can't you have an x so assignment semantics are of the form an L value versus an R value so the way to think about this is really easy an L value can go on the left hand side of an assignment semantics so an L value also has a location associated with it right you have L's two ways to remember that it's on the left hand side of an assignment operator and it has a location associated with it where an R value is just a value it has no location associated with it so this is something like we saw of the form of x equals 5 right, x is an L value that has a location associated with it 5 it does not have location associated with it it's just an R value so here we're going to find this a little bit more broadly because it's going to come into play a different thing so an expression is an L value if there is a location associated with that expression so why is this a little bit more general than what we were just talking about if the L value is a literal if there is a location associated with it right, so we talked about so we put x on the left hand side of it what are we saying that just things, like variable things like x and y can be L values what are we specifically saying in our definition an expression, what's an expression these and operators so we didn't really ever define it but we talked about the line of programming like we did, so we have programs and statements and statements that are composed of multiple expressions so anyway we have function calls operators, we can call a function and then add this as all of that function to the result of another function this can be any complicated expression that you have the point of view references, adders of operators all these things so if there is an L value associated with the expression then it can be on the left hand side R value so expression is an R value if the expression has a little value associated with the expression then function 5, does that have a value associated with it does x have a value associated with it it has a location associated with x assuming that x is already declared but we'll assume well formed programs here so x as R even declares we know there is a location associated with x the same as addition operators we have 5 plus 10 does the result of that have a value associated with it we see some value as the result of that operation where x plus y is the same thing so here we have x equals y when L value equals to an R value and so the semantics here for anything of an L value is equal to an R value is copy the value in the R value to the location in the L value associated with the L value whereas this is why we can't do 5 equals x this does not make sense semantically we already talked about that we cannot do that we can have an L value on the left side and an L value on the right side when do we see that x equals x or x equals 5 and here the semantics are slightly different but still essentially the same copy the value of the location associated with the L value on the right hand side to the location associated with the L value on the left hand side cool so now your thing is like C so A is which type of value an L value or an R value an L value and B plus C is so the R value here is the value in the location associated with B adding to the value in the location associated with C that expression together is a value so what we need here is copy the value associated with B plus C with A midterm on Friday I'm going to do a minute off