 Alright, let's get started. We have a lot of, not quite a full house, so that's kind of nice. Any questions before we get started? I found out this desk moves up and down. It's kind of cool. It's really weird. I don't want the desk up here because I can't see all of the beautiful people. So let's start off primary left off on Wednesday. So what we've been talking about here is we've been talking about scopes and specifically how to resolve and how to determine what a name is in a program. So what does it semantically mean when we see identifier or a name? And so we talked about how long, once a name is declared, how long is that name valid for? Is it only valid till the end of that function? Is it valid until the end of that program? Is it valid forever and ever and nobody else could ever use a different name? And so the flip side of this question, so one question is okay, when I declare a name, how long is that name valid for? So that's one side of the equation. The flip side is when I see a name in a program, how do I map that back to its declaration? So how do I resolve? So this is called a resolution of how to map a name back to a declaration. And scope, so we've kind of talked about scope. I think up till now you've learned a bit about scope. So we talked about it now and what we're going to do is we're going to define the different types of scoping and how you can do scoping. So I like to think of it as scope in the semantic behind answering these two questions. So how long is a declaration valid? So when something is declared, a variable is declared, a function is declared, how long is that declaration valid for? Where kind of long is kind of this abstract term? And the flip side is okay, how do we resolve a name? So if we see a name, how do we know what declaration that maps to it? So what does, as far as terms of length goes, how does C do, what's the C scoping rule? The braces to what? Yeah, so C does what's called block level scoping, right? So whenever you declare something, it's valid in between those braces that it's declared in. And so declarations are valid in that block that they're declared in. What about if a declaration is not in a block? It becomes global. So what does that mean? What does global mean? Is that valid for the entire file that it lives in? Is that true? I don't remember. Is it false? Yeah. If it's in the header file. Right, so yeah, so it is valid in that file that it's declared in, right? So that's part of what global is. If it's not declared in a block, it's going to be valid from that declaration until the end of the file. But also it can be included by other files and other programs. And other programs can call access that function or that variable. What about if the static operators apply to a global variable? How does that change things? Yeah. The common truth of that variable is that it's not an active variable and an object. I'm talking about in C, so no object. So global declarations with the static. Yeah, it's just a part of that statement. Yeah, so just a file. So that does actually restrict the definition to say only this variable is only accessible in this file. And no other file is going to include it or call that definition. So this is from what we just said in here. So what about JavaScript? Maybe we have a familiar area with JavaScript. Yeah. Can you talk to an object model? No, I'm talking about scoping. So C uses block-level scoping. What does JavaScript use? Yes, but how? I guess so there are global variables in JavaScript, right, definitely. What about just the standard, like if you declare something, how long? It's like every declaration of a variable is not, unless it's in a function. Okay, there we go. So yeah. So JavaScript uses function-level scoping, actually. And so that's why you have to use crazy tricks, like if you want to restrict. So you can't just put braces around something. And so you can't have variables specifically in an if statement or an else statement. The variables are declared for that whole function. So you have to do a lot of tricks and you create these functions just to restrict the access of a variable. So that's a common trick in JavaScript, right? Because otherwise, if you do declare globally, it's accessible. If there is no static or anything like that, anybody can access it. And so yeah, deferring to the value in the function that they declared. So does everybody get the semantic difference between the two here? Yeah, questions about that? Okay, so this is one half of the scoping rules, right? So this does the, how long is something valid for, a declaration valid for? Okay, so we're going to look at an example. So here I've got a C program. So remember, we're talking about now C style scoping. And I've got a main function. And in that main function, so these braces here for this function introduce a new scope, right? So it's got block level scope. These braces here define a new block. But there's no restriction. I can define more blocks. So I can define another block. And inside that, I can have an integer called i. I can set i to be whatever I want, 10,000. And then I can print out i. And then I can define another block outside of this. And I can print out i. So what's going to happen when I compile this program? Error with an error. Error with an error. It's a power one slide to take power one slide. That's a syntax error. Syntax error, is there a syntax error in this program? It could be. There's not an intended syntax error. Let's put that. Yeah, so which variable can you reference out of stone? Which i? So the second printout statement, right? So in this block here, I'm referring to, so remember, scoping affects how to map a name to a declaration. So when I see this i, so here we're assigning 10,000 to i. I know how to look up and we'll get into how exactly we look up. But I know that, hey, this i refers to this declaration of i. So now when I say print out that i, this variable, this name i maps to this declaration of i. But we talked about, right? So c has block level scoping rules. So this i is only valid in the block that it's declared in. And it's not valid outside of that block. So when I try to use this name i, the compiler goes, I don't know what that name refers to. So this thing has been declared as the name i. And so it's going to give me this error depending on exactly which file you use, yeah? But not in that first. We'll get to it, we'll get to it. Yeah, so this is just kind of showing that, hey, there's the, you, yeah, so this is just to show that things are local to that block. So you can't access that same declaration in the block outside of it. So yeah, this i is valid in this block here. And so those i's all correspond to that same declaration, but this last i doesn't have anything that it resolves to. So that's how the compiler says, hey, i is undeclared. You've never stated, you've never declared that there's a name called i. And what is it? Is it a variable, is it a function? I don't know what it is. Okay, so let's try and fix it. So now we have our program, we've got our first block. We've got i, we're setting i to be 10,000, we're printing out i. And then we're going to declare i and then print out i. So will I be able to compile this program? Yes. Yes. So I guess another way to ask that question is, will there be an undeclared identifier error when I compile this? No. No? Why? Yeah. You declared all variables. The second i is contained in the same, but it's still declared. Alright, we'll get to that in a second. Yes, so it is properly declared, right? So at least the compiler will know, hey, this reference of i corresponds to this declaration of i. So here's maybe a curveball question. Where does the printf come from? Is the printf a name that we need to specify and we need to resolve? Yes. Yes? Yeah, so where does it live? Is it? Where does it live? In which header file? Yeah, so standardio.h we can assume, actually, so if you go look up the definition, you'll see that the stdio.h includes a definition or a declaration of the printf function. And the way headers work in C, all that's essentially happening here is when we do this pounding clue, and paste whatever's in standardio.h right here. And so that's why we have access to those declarations. Okay, so I can compile this. If you're very astute, you may have noticed that we removed the warning errors from our compilation. So what's it going to print out when I compile this program? What's the first thing it's going to print out? Ten thousand. Ten thousand, right? So it's going to go into this block, it's going to print out i, where we know this i refers to this declaration of i, and we know that the i that we set to be ten thousand is also the same declaration. So they both refer to the same variable. So we'll print out ten, it's a hundred thousand. We'll print out a hundred thousand. So what's the next thing it's going to print out? Oh, is it wrong? That's wrong. That's weird. Alright, so what's the next thing it's going to print out? Whatever value it comes from the address, it's the same. Okay, maybe true. What else is that other stuff? What's some other stuff that was that? Is it going to print out... So I guess what's the C standard say it can or should print out? Yeah. Some language is at zero? So what do you mean in some language is at zero? Set what to zero? Why? Okay, that's only for the default, right? So the problem here is we've never initialized this i. So this declaration of i in the second block is a new declaration of i that is completely separate from the i in the first block. So this assignment of ten thousand to i in this first block only affects that variable in the first block. But when we declare a new i in the second block, well now that has never been assigned to. So it's uninitialized. So on this example, which is I think the... Yeah, this first example was the sent OS 6.7. So it just outputs zero because, like you said, that just happens to be the value that's in that memory address. But the C specification says that any uninitialized, like taking the value of an uninitialized variable it could be anything. So the implementation is free to do whatever it wants. It could zero all the values explicitly. It could just print out whatever's there. So running it on my laptop, I can compile it. It's going to print out something completely different. Different compilers, different operating systems. So this kind of illustrates hopefully two concepts. So while this program is valid, and syntactically valid, we can compile it. It's also more or less semantically valid because the C compiler, the C standard doesn't say you can't use an uninitialized variable. It just says that the value of that uninitialized variable is unknown. So that's how we get two different values here, but it's still kind of okay. But if you turn on warnings, so this is why in all of the examples and all the homeworks, we say turn on all warnings because the compiler will issue a warning that says, hey, you're using an uninitialized variable. It's probably not what you meant to do. Questions on this example? Yeah. Yeah, just that. Number got to 166 months. Is that supposed to be good? I think in this implementation it ends up being whatever is in the memory address that's on the stack right there at that point. So in this case, it happens to be probably a memory address. I didn't really look into it further. But it could be anything. The compiler could just say, I'm going to print out 42 whatever I want. I'm going to set that to be that value. It's just as valid as either of these two implementations. Any other questions? Say that again? Same as heat memory. No. So heat memory is created when you call malloc. Malloc, you're creating some object on the heat. I'm saying, I'm saying. No, because right here we're just talking about the names. So whenever you allocate some object on the heat, you have to give it a name, otherwise you can never refer to it again later. So this is all only talking about names. You don't have to initialize a heat object. You do because you just get back a chunk of memory. Yes, so if you get back from malloc, it's a pointer, right? So it's a pointer to some memory that has. So if you try to say what's at that pointer, it's going to be garbage until you assign it. So yeah, I guess you can have assignment semantics here or the same, but kind of what we're talking about here is resolving that name I. I could be a pointer that's declared. It could be whatever. Okay, so when we see a name, right? When we're trying to analyze a program or understand a program, right? When we see a name, we need to map that name to a declaration so that assignments happen to the same declaration and so that when we print things out, when we access variables, they all refer to the same thing. So to do this, we use a data structure that we're going to call a symbol table. And it's actually incredibly simple. So it's mapping names to declarations and attributes. So what would be some attributes? The name's kind of easy, right? It's the name of whatever thing. But what's an attribute that we might want? Yeah? Like variables that you have to pass over a function. So yeah, so if it was a function, right? So a function is just a name. It has a name. It has some declaration where that function was declared. It also has a body where that function was defined. So the body may be an attribute. The parameters that we pass to that function is an attribute. Maybe, maybe, maybe not. But yeah, definitely one of them. What else? Yeah? The pieces of data is sort of an instructive of the attributes. Yeah, so when we define an attribute, sorry, when we define a struct, a struct is declared and then each of the types and names of each of its struct elements, is that right, are declared? So we have to keep track of those. When we see that struct later, we need to know if it's being accessed correctly. What about just a regular old variable? What are some attributes that variables have? Yeah? Public, private, static. Yeah, public, private, static. What else? Const. Const, if it's constant. Well, it looks like more basic than all of those things. Yeah? Variable type. Yeah, the type. Yeah, the type of the variable, right? We want to be able to map that name back to the declaration where that type of the variable is declared. And so that's basically all a simple table does. It's just a huge table that maps a name to the declaration and an attribute. And attributes. Okay, so there's two major types of scoping that we're going to try right here. These are very important to understand. One is static scoping. So this is one that actually we're probably almost familiar with in our big day programming because the majority of modern languages have some form of static scoping. And so the idea here, like it says in the name, is that the resolution of a name to a declaration is done statically at compile time. And so the way I like to think about this with a simple table is the compiler creates the simple table as it's going through the code and creates a simple table so it knows how to resolve future names, future references back to the decorations. And so it's doing this all statically at compile time. So it's the opposite of doing something statically. Doing it dynamically, right? Or the other way of doing it at runtime. So the other way to do this is to do what's called dynamic scoping. And in this case, we actually are resolving names to declarations dynamically at runtime. So this means that just looking at the code, you may not be able to tell exactly what decoration and name references because it could change depending on the runtime behavior of the program. And so the way this is implemented and the way to think about it is in this way the simple table is going to be created dynamically. So the compiler puts code in there to keep track of the simple table as the program is executed. So when functions are called or do blocks are hit, decorations are added to the simple table and then when functions return, decorations are going to leave the simple table. So we're going to see an example of that. Maybe we have high level questions on these two concepts or even any questions on these concepts. Yeah. Would C be static scoping? Would C be static scoping? Yes. So C is static scoping, so I guess why. Because it's easier. How do you know that it has static scoping? It's maybe a more tricky question than I intended. So one way would be you look at the specification and it tells you exactly what the scoping rules are. Nobody ever does that. So how would you know from your own experience with C or C++ why it would be static scoping? Do you want to keep going or do you want to pass it on? You can't turn a string into a name. You can't turn a string into a name. So that is true. But it's actually not the difference between static and dynamic scoping. So we're going to get into it. The only time I've ever seen dynamic scoping is with objects in classes in an object-oriented program. So define polymorphic pointers. C doesn't have that. Okay. So you can have a language that is object-oriented and static scoping. So Java, object-oriented, and static scoping. Yeah, all of them do, but the object-oriented allows you to do it in the class. Still no. That's good. There are a lot of things that happen at runtime with objects. You can't change what a function does at runtime. Yeah, I'm not sure if that's true. Because you can pass in pointers to functions. If you call the pointer to the function you can pass in different functions. That's not actually oftentimes with the name. That's true. So the big point is here, when you see a name in a C program, like a call to a function, you know it only maps to one declaration of that name. Now if that name is a parameter value, maybe the runtime behavior, the value of those parameters will change. But what that name refers to is not going to change. So yeah, the way the kind of high level way I like to think about it is dynamically scoped. It's almost like everything is global in some sense. So when something's declared any other function can now access that variable and any function that calls that can change that. So we'll see an example in a second. But yeah, so you can look at a piece of C or Java code and say I know whenever this variable is referenced I can always map that to a declaration. You can map it to that block that it's declared in or the header file that it's declared in, whatever. You can always statically map that and it's never going to change. So let's look at an example. Is Python dynamic scoping? No. This may be one of these really tricky things. So even though Python is dynamically typed and a variable can have more than one type throughout its lifetime, a variable is only ever going to be known statically what that variable refers to. You may have an example here. Common list or some list variance allow you to define variables that are dynamically typed. So it's actually kind of cool you can decide which ones you want to use for different variables. Other languages like older versions of Perl were dynamically typed. But recently now I think that's an option. So there are some languages that do it but not a lot. Yeah. Is this dynamic typing or dynamic scoping? Scoping. So I'm not dynamic typing to talk about Python because it gets confusing because it does have dynamic types but a static scoping. So they're distinct concepts. Okay. So here's our simple C program. We're going to look at it. We're going to walk through it both in a normal C with static scoping and then we're going to walk through it in dynamic scoping to see under behavior an execution of the code actually changes. So this will be something that you'll need to do so that way you make sure you understand the differences here. Okay. So here I'm including this header file presumably to find a bunch of stuff. I'm declaring an integer X. So what's the scope of this integer? Global. Yeah. So in this file it's from here to the end of the file that include this object file called an X as this I or this X. I'm going to declare a function bar. So what am I actually declaring here? Yeah, I guess I'm going to say that. So what... Why don't you reshape what I just said? It's a prototype. Basically you're allowing the compiler because it's a single pass compiler to know that anywhere that this function actually exists so that when you come to it it's not like, oh, where is this? Right. So here actually I'm declaring a function. I'm saying there is a function called bar that takes in no parameters and returns nothing. I'm declaring it but I'm not actually defining the body of that function. So the compiler when it's processing this can actually create and entering a symbol table for the main bar. So it can still map bar, like the main bar to this declaration and the attributes but it just won't know until later where that's actually defined. Okay, so we declare bar then we define a function called foo and inside foo we're going to define a character C so where is this character C valid in? Within the block foo? Yeah, exactly. Okay. So we're going to set a variable C we're going to call bar we're going to print out X space C then we're going to define a function called baz and baz has not been called yet so we can see here that we've called bar within foo, right? Right here, the second line of foo so this is why we need that declaration before defining foo is we need to have bar to bar. Okay. So let me look at the function of baz, it's going to print out the variable by the name of X and then it's going to set X to be 1337 Now here's where we define we actually define bar, the body of bar and we say okay bar is going to set X to be 100 then it's going to call baz and then we finally get to our main function so the main function is going to set X to be 10 and then inside of a new block we're going to define a character pointer called X and we're going to set it equal to the constant spring testing or the constant character array testing and then we're going to print out X and then we're going to call foo Okay, so questions on this code about what anything, about what it's doing or does or who calls what Yeah Yes, but I was running out of space so I did not do that I think I did it in the one that I actually ran up the file, but yeah Yeah Why are you declaring testing as a character pointer and you're printing out X rather than a reference to? Oh, it's because the semantics of the printS format string percent S takes in a card star, a pointer so it derepenses that pointer and prints out whatever thing until it gets to a zero Any questions? I thought you were going to ask I just created something and then passed it to something else and that's clear for example purposes Any other questions? What's the code? Have you got it? So what's the order of function calls? So what's the first function that's going to be called? May and then foo Now what's foo going to call? Bar, what's bar going to call? Baz, and then we call back up, go back up and then we exit So So we talked about this We're talking statically scoping now So this declaration of X in X because it's global it's going to be valid from that declaration of X all the way to the end of the program to the end of this file and also in other files that we're only talking about this one so that's all we're going to think about So where is bar valid from? So what we're starting here on the right is the length, the scope, the time the amount of code that that X is valid for So what about bar? I think it's just one line less Yeah one line less So it starts there at bar So even though bar is actually defined, the body of bar is defined later we can refer to bar as a function all the way from when it's declared to the end of the file Ok, foo Yeah Nope No, so it's randomly calling on people One more line down Yeah one more line down Ok foo, we're not going to do that for any other function You can see One of the things is to ask yourself why are these defined from where they are to the end of the function So we talked about with X but why is foo valid there to the end of the file So in this case foo is not defined in a block So foo is the name The name is being declared in the global scope So that's why it has the same scope as in X So this is one of the things I want you to kind of try to wrap your hand around There's no difference here So if you were just talking about names There's no difference between X and foo and bar and baz It just happens to be that bar and baz they're actually we'd say that they're functions function signature which we'll talk about in a second and X happens to be an integer but as far as we care more compiling it we need to be able to figure that out later on when we see this bar because what if we had put X brackets, right, we tried to call X What would that be? Is it actually a syntax error though? Is it not syntactically valid? It's not semantically valid, right exactly because we can't call an integer We can call a function We can call names So syntactically that's all we care about is we have name, parentheses maybe something that's separated by commas and then an end in parentheses but that's all we care about but semantically when we want to say is this a valid call we need to map that name to the declaration and see is that declaration a function or is it an integer So where's C is defined in this block so it's scoping is just those three lines of foo What about the integer X in bar how far just within that block so it's just defined in that block and the other thing to note here it doesn't matter that there's already an X defined globally so we'll get into the specifics there and the other in this last block here there is a character pointer called okay so the question is so now we're going to do is we want to resolve all these names to their declarations so we're the compiler you can think about it, we're kind of just going through the program from the top to the bottom looking for all the names and trying to map them to declarations we're going to create an entry in our symbol table with all the attributes and wherever we see a name we want to try and map that back so what happens if we when we see this bar name what do we map that to was it? yeah so we map it well let's go to the scoping rule so we're going to map it to that bar so we know that that bar is referring to that bar that we declared a couple lines above okay what about the x in this print depth the global x so it's going to be here and that's because x is declared globally and we can look statically here and we look outside the scopes and we say okay is there an x declared in your block? no is there an x declared in the global scope? yes there is an integer x so that means that this refers to the name x we're about to see yeah the one within foob so by the same logic we're going to look at this c and say okay is there anything in my block in this encompassing block yes there is a a variable called c and it's type as a character okay and then we go through and say okay printf where was printf defined yeah standardio.h we talked about that that's good and then we just keep going so then we look at this x okay where is this x? not through the global x exactly so this x when we see this name we know it's the same decoration as that x on line 2 okay now going out what about this x same thing global x right or is it this one? why not it's not in the same block right it's not in the same scope so this integer x is only defined in the scope of the function bar so the x in main can't access that it can only access the global x which is okay and then also so can it dip into this other scope to talk to this x? no it also can so it's got to actually and statically remember we're doing this statically so we know that this x maps to that integer x okay now when we see this x though now we say well are there any x's anything but a main x in its surrounding block we say yeah there's actually a character pointer called x here and so we can use that so this is where so I don't think we're going to call it out specifically but so we've probably learned about shadow shadowing of variables in scopes yes no no okay so in this block here can this x ever refer to that global integer x? not in c good answer yeah so no we're using c we can't ever get to that global i sorry that global integer x because every time we use the name x in this block we're going to refer to that character pointer that's defined at the beginning of the block so it's called shadowing in effect we shadow the global x we can never reach it okay so what's going to happen when I compile this is it going to get any errors yeah say that again ah if we give an error it's a tricky question so like a compile time error maybe depending on how smart your compiler is if it can read the string here but yes if you try to do that at runtime instead of printing out the string testing you print out I think a pointer to that string so you'd be printing out whatever is in the value x there yeah in the full method you are saying the scope is from the third the full line to the end right here sometimes we call that method before the declaration and even then compiler doesn't give that so call which function so again using the full before the full line in my function then it won't give me the error right no it will so you can't and C is very strict if you have to define you have to declare food before you use it so this is why like if we try to remove this void bar here even though we're defining bar later down C will complain and say hey I don't know you're making this called a bar I've never seen bars and uninitialized like we're it's undeclared so this is why scoping rules get very complicated depending on language so yeah in Java the scope of well in this case you don't ever really have you very rarely have global functions I don't even know if you can have that Java right so you have the classes and you have functions that are inside of each class and there the scope actually extends both ways so it extends so all you have to do is define a function that you can declare or call it from any other function so yes it's you could think about doing that in C you could do that right you just have to do you make one pass looking for all of the global functions global functions and global variables and then you go back and recompile but they chose not to do that in their language okay cool good question alright so what happens when I compile this is they're gonna be in America the x in BAS the x in BAS this one yeah it hasn't been initialized yet how do you know called bar right but where's bar called so that's so hey that's a good question right so if you just look at this from top to bottom right we don't really know if x is gonna be initialized before we get to bar but that's actually why checking for use of initialized variables is very difficult especially in this case where it's a global variable right so anything could happen before we get to BAS right and one of those things that could have happened is somebody could assign a value to x before it gets to us so it could be some of the time there's an initialized variable there could be some program pass where nobody initializes it and there could be some program pass where it's always initialized so it's a lot easier for the compiler to tell when it's a local variable because it knows only these instructions are going to be executed so I can make a statement that I know the exact order these things happen in whereas in this case I don't really know the entire order of everything that's going to be called before we get to BAS so are there going to be any other errors on compilation sure it will complain about the lack of return value on the say you fixed that okay so it compiles yeah can you repeat the part on the shadow with the x so today's idea is here in this x so when we get to this block right this name x inside this block will always map to this character pointer x this declaration even though globally there is an integer x declared the way the scoping resolution the scoping resolution works we go inside out so we always look in our local scope and then if we can't find it there we look in our enclosing scope and the enclosing scope until we find that name or if we don't find it we can call it an error yeah in bar isn't that shadowing as well because you make a local event in bar yes in bar it's also shadowing except that we don't actually reference that x but yes x is also shadowed here exactly yes cool any other questions okay what happens when we run it so it's the first thing it's going to print out yeah okay question oh okay so so if you put in x equals x so in this case actually that's a very question I'm not 100% certain I think in general it's an error and the compiler should complain if you try to use the same name in in the assignment of a declaration so I think it would I think in this case it would look at the x first and then say you're trying to assign x to x and it shouldn't work but that's the question you get a warning I think I guess the question is is it going to work if you have a global variable also called x like is it going to use that one I don't think it would use that one but yeah that would be good somebody should well do that later it's definitely not during class but if you did you should tell us okay so we execute this program it's the first thing it's going to output testing from which function main so we hit this printf right we start in main so what's so when we get when we print out testing so the value in our local scope of x is testing but what's the global value of x yeah so so then we call foo and then what's the next what's so then we call foo and then we set a character star is equal to c we call bar we go down here we set this local x to be 1,200 we call baz and then we print out x so what's this x going to print out 10 right so statically we know this x is this global x and we set that earlier in the main function to be 10 on this one so this is going to so we'll see testing we'll see 10 and then this is going to set x to 1 through 3 7 so what's which x is this referring to again global one because the global x is going to have 1,337 Baz is going to return bar is going to return and then we're going to print out x and c so what's this going to print out 1 through 3 7 space c and then foo will return and then main will return and everything will be awesome and so you can see that well we knew exactly which name was being assigned to in each of these functions right statically we can look at this and we can say oh this x is always referring to here and this x in Baz is always referring to this global x so that x in Baz is never going to change and somehow point to this x in bar so questions about static scoping this should be kind of the easy ish one because this is what you do all the time so then we look at the flip side so dynamic scoping so as we said the symbol table is going to be created and updated at run time as the program is executed so that when we want to resolve some name let's say x we have to look it up in the symbol table for the last encounter of that declaration with the name x and that's what we're going to refer to so because of this x could change depending on how a function is called here you think each function or each block in the call stack is going to add its own decorations to the symbol table at run time therefore if you have a function that references what would normally be a global variable x it could actually reference a variable x in a different block depending on how it's called so yeah common list allows both as I said so this kind of makes it a little bit crazy why it didn't really catch on okay so remember this is all happening dynamically so we're going to think about executing this function we're going to kind of just pass through it first getting all of the you can think about maybe for an interpreter you're going to start at the beginning we're going to look at all of the global declarations until we get to the main and then we're going to start executing main so what I'm going to do is this time I'm going to show the symbol table as we go so when I hit this declaration x so let's see in my symbol table I'm going to create an entry for the name x I'm going to say it has the attribute of integer and on the right hand side I'm going to show the value but currently it has no value you haven't assigned anything to it so then I go to bar and I'm going to create a name called bar in my global in my symbol table here in the global scope and I'm going to say okay bar let's say so here I'm kind of we're going to get to it next or next next but you can think of the parameters so yeah the inside the brackets is the parameters that we're passing into bar in this case well there's nothing, there's no parameters to bar so we're going to represent that as void okay so then we're going to go to foo and we're going to say okay we've declared a foo and we've seen a function called foo and we know it has also it's named as foo, it's a function it has the parameters, it has no parameters but we also have we're also going to say here that it's also defined online form so why don't we have a line definition for bar yeah we don't have the definition yet we've just seen the declaration right we have nothing so we put nothing right now okay so we call foo, we see foo we do the same thing with baz we say baz is on line 9 and then we get to bar now here we can go to our symbol table look up and say okay do we have anything named bar yes we do actually and something about that doesn't have the definition so we can go there update in our symbol table that actually bar lives on let's say on line 13 and then we keep going and we go to main and we're going to say okay now we actually have a function we see a function main its type is also void and it lives on line 17 so so let's say we went to the global scope of our program once so we create this symbol table so this is the global scope of our dynamic symbol table so now we're actually going to start executing main so when we hit this x what does this x result to global x so this x so all we do remember is look in our dynamic symbol table which is full of the global scope right now look up is there an x yeah there's an x great we're going to set its value equal to 10 and then we'll be good so then we're going to go into this block now excuse me now remember scope here is going to be updated dynamically so when we get to a new block we're going to actually create a new scope here and so I'm going to kind of represent that with like an arrow in our table we see this character x we're now going to create a new entry in our symbol table called with the name of x and what's the type of x going to be character pointer and it's going to have the value testing so we're going to create that in our symbol table dynamically then we get to this print dev so what does this x refer to testing right yeah so this x is going to refer so we're looking in our table right from our closest scope out to the first occurrence of the name x so in this case right there's a name x in our closest scope and so we're going to say okay this x has the value testing so I know which one that is so I'm going to be able to print that out okay the one happens when I read this scope it goes away yeah exactly so this we're going to completely get rid of this scope because we know we've executed that block we'll never be able to access those names anymore so they go away questions so far so has there been any difference yes no not yet foreshadowing the answer okay so now we call the function foo so we looked at we see we see a name foo we actually looked that up in the symbol table and say oh foo's on line 4 go start executing line 4 so we jump into line 4 and now once again so have we created a new scope yes so which scope is this the foo scope the foo scope yeah so yeah the scope of the block foo right so we're going to create a new scope here we're going to say okay there's a character c defined here in this new scope that has the value of c so then we're going to go we're going to execute bar and when we go into bar what are we going to do scope yeah create a new scope so we're going to create a new scope again because we're now in the scope of bar and we're going to say okay we're creating what variable name are we declaring here x which is an integer if we're setting the value 100 so here we're creating in our symbol table name x attribute int value 100 so then we're going to bas we're finally called bas and we get into bas we would create a new scope normally but we can kind of see here there's no decorations so it doesn't really matter maybe an empty scope now when we see this x what is this x referring to you'd be a little bit more specific that's probably correct the x on the screen the x that's at that's at 100 so y right so we look up we see the x we look it up in our symbol table and remember this bottom most layer of the symbol table is closest to our block so we're going to look up starting from there and looking in each scope so we look and we see oh yeah I see an x and its value is 100 so I'm going to print out there I'm going to refer to 100 there and I'm going to print out 100 so that x is going to refer to this 100 from this table so is there a difference here so this is dynamic scoping this is what makes it crazy so if a function defines a new so that block is valid not just syntactically for these two lines but that's valid for any other function calls after that inside that function so anything that that function calls can refer to variables that are in that out the enclosing block and so it's kind of so maybe I'll talk about it at the end but this is actually a simpler way to program an interpreter and that's why a lot of earlier languages would do this because it's actually easier to code than doing this all statically because you can just do this at runtime and as the interpreter you can just build this exact table so you know exactly what the values of everything are so this is going to print out 100 so it's not referring we did statically to this global x because the global x is actually shadowed by that declaration of x in bar so this just happens to be dynamic as this shadow is happening but now we can't actually refer to that global x so let's go to the next one so what are we going to set which x does this name refer to I guess what value does the x have that this is referring to 100 so we're going to look it up in the table we're going to see ok this x is over here so I'm going to set this value of 100 to 1337 and then I'm going to start executing ok so when I get to the end of this function BAS normally I would clean up its scope but nothing was defined in BAS so I'm going to return into bar and then at the end of bar I'm going to clean up the scope so this is just like when we left the scope outside of main so here when I clean up the scope of bar what am I getting rid of the x with what the x with the x with 1337 so I'm going to clean so this is now out of this block so I'm going to you can think of it kind of like a stack right yeah I'm going to pop this off and now when we return I get rid of that and now so I return from this bar function now I'm at the print death function so now what does C refer to C the value of C right so C when we see this reference to C we're going to look it up in the table we're going to say oh it's in this local scope so this C refers to this as this value of C okay now what about x yeah x100 so it's going to map to this definition of x here and then foo is going to return so we're going to clean up and get rid of this character C in our simple table so we're going to return and foo is going to return and clean up sorry main is going to return and clean amazing main and now we're done so okay so assuming we had some crazy dynamic scoping GCC compiler that actually did this no I don't think so that would be a good project maybe yeah so no this is not a real command I guess I should have called it imaginary CC or something but anyways the point is we could compile this with a fake compiler we could use a fake compiler and say there's no errors now when I run this program we're only going to fake program so it would be the first thing testing yeah what's the next thing 10 100 10C 137C 10C so why isn't it 137 right so oh yeah once we leave once we leave BAS once we leave BAR we're not referring to the global in X and not the one in the scope of BAR exactly so even though BAS set X to be 137 and statically this X refers to the global X but because dynamically BAR defined a new variable X before it called BAS now that X in BAR got changed to 137 but then when it returned it went away we don't care about it anymore so let's go back to the printf here in foo which is the last thing that's going to be printed out this X is going to refer to the global X which was 10 which means that so yeah it should be 10C it's a lot easier to know how to compile it yeah is there a practical use to shadowing or is it just something you should probably avoid by having multiple types of multiple variables is there a practical use to shadowing possibly there's a think of enough use cases there's going to be a practical use for anything generally I don't know it can be nice well it depends on your language if the language can be really terrible and it's really easy to create global variables there's a good chance that the name you want like size you want it to refer to your size and your function not some function size that's defined in the library or in those kind of cases yeah generally it's probably a mistake maybe you don't want to do that some languages actually like python I believe you have to use a keyword global to say that hey this local variable in this scope I actually want to refer to the local version of this variable and not to create a new variable that shadows the whole value yeah it depends on the language maybe so for something like C for C you can't define a function inside of another function so like I don't know if this is 100% true but I'd say all the functions in C have to be globally scoped so is that right exactly so that would be in the case where you couldn't like declare a foo here it would throw an error you could think about maybe it should shadow it for the rest of the file but it depends on the semantics of the language like what happens if the name already exists and it exists in scope I think with C++ you can use the scope the double the two colons to disambiguate if there's a problem other questions so this is something you should be familiar with so if I gave you some code like this and say what is it static scoping dynamic scoping you'd be able to definitely do that alright okay so one of the things we talked about is function resolution right so we talked about okay resolving a name to a specific declaration but how do we resolve a function called to the appropriate function right we need some way to map that and once again this gets back to the idea of semantics and the answer is really it depends depending on the language um so what are some ways we can use to disambiguate between functions yeah what's the big thing what's more general than that different name right yeah you just say oh there's foo1, foo2, foo3, foo10 foo100 or whatever right yeah you just create new names so that would be one way so parameters would be another way what about what else besides parameters what else could you use yeah yeah you could use a return type right so you could use maybe the combination of name and return type need to be unique so we talked about well you could do um so parameters are also kind of you can have different granularities right so you could say hey let's do names and the number of parameters right so you can define a function foo and you define a function foo with two parameters but you can never define another function foo with two parameters so any function foo that's called the two parameters match directly to that function um this can get into problems maybe we want to do names plus parameter number plus parameter types so actually the types of the parameters so I could define a function foo that takes in strings or that takes in integers right and the compiler can hopefully figure out which one's which uh anything else is there anything super weird okay namespaces yeah that's a good uh something I didn't think about so yeah you could give the programmer a way to specify a new scope right that's kind of better than just blocks so you could say hey everything in here is in the project of a namespace I don't know so utils or something and then later on you could refer to those functions as util dot something or util pull in something or hardly have a way to specify the namespace so yeah that's a good one anything else parameter order uh so yeah I okay yeah that's good um I'm gonna go ahead and say the types here are in an order right from zero to whatever actually one thing I didn't specify here is what about like maybe the names of the parameter of the parameter so maybe you could think about having different functions that have the same number of parameters the same types but they have different names of parameters and so that could help this end of the way we're making up languages here parameters correct I just kind of made it explicit here um but yeah you think about like functions some languages you can call functions by specifying like when you're calling a function you can specify the keyword or you can specify which parameters you don't actually have to be positional so maybe there's something there I don't know so these are kind of so these disambiguation rules right so these ways of distinguishing between different definitions of the same of the same name function uh they're often referred to as I have to think of them as the function signature right so what's nice I don't know if that's true what's nice about a signature yeah so it should be something unique it should be unique right so it should be a way to when you're defining it to know hey has the function with this signature already been uh declared or defined if so then there's an error and you can say well when I see a function called I know which function to go to so can I tell just from the function call can I tell what function signature was meant to be called for and it's very completely by program language so what does C use as the function signatures was it sorry I guess you can guess it's okay I have to look it up too yeah name name so yeah something that actually very surprised me yeah and see it's only the name so you can't create a function foo that has two parameters and a function foo that only takes one parameter so the compiler will complain because the names have to be unique so yeah so I had to kind of think of it as a vector so it kind of ends up more formally defining it so I can think about okay so this the function signature would just be a vector for me to make okay in C plus plus what do you function signature what's the function signature in C plus plus what so names plus parameter types is it half the return type can you define a function with the same name same parameters with different return types no why yeah so implicit passing you want to expand a little bit right so the point is that we want to resolve it when we see it being used right so you could if you were yeah so because of the implicit conversions right so I may take and actually I could not use what about you don't use the return value of the function food right so I'm going to have to use it so then I could call a function food pass it to arguments do nothing with the return call and then the compiler would have no way of knowing which function I meant with the return type so you could think about you could do in languages but in C plus plus and I want to say Java as well it's mostly the same way so they pretty much take the signature is the name and the type of parameter one the type of parameter two type of parameter three for excuse me however many parameters there are okay so this leads us to handy situations where we want to do function resolution so now we're going to look at a C plus plus example that's also mostly C maybe because I tried this in C and it's like oh this doesn't work that's interesting I could put that in the lecture so we're going to find a function food that returns an integer and takes in zero parameters and it's going to return ten okay and so very simple function right so I'm going to find another function food that takes in an integer and it's going to return ten plus whatever we pass in so in my function main so if I I call food so which food does this match to the first one how do you know it's the first one no parameters no parameters in the call so remember the important thing here is that we're looking at this call and saying can I go back from this call to that name and so the question is well can I generate a function signature off of this call yes I can look at this I can see I know the name of this function is supposed to be food and that has zero parameters so that's my function signature and so I can look up hey yeah there's a there's a function food defined with zero parameters perfect that matches great then later on when I call bar right so when I call see this food so now which food is this correspond to second one the first one second one why so test is defined here right so so which which food second one why right right because it so just by looking at this right without even thinking about the types per second but I can look at this second function call food and I can see okay the name is food and they're passing in one argument right one parameter so that's probably that's enough in this case but I also know the types of the variables and I can see oh the type of this variable test is an integer so I know that it's not only it's the name of food and its first parameters and I can look and see ah yes there's a declaration of food where it has one parameter whose type is an int so I know that this food maps to that function called food so when I run it do I have the thing here yeah okay so when I run it what is this going to output so is it going to compile yeah is there going to be any errors no what's it going to output somebody want to say that louder than a mumble yeah 10 space 20 so test is going to have the value of 10 and bar is going to have the value of 20 is that correct does that agree maybe disagree yeah 10 and 20 okay cool okay so we'll talk very quickly about assignment semantics before we go I've given a little preview of where we're headed so okay so we talked about scoping so how to define how to map a name to the declaration the place where it's declared we talked about how to define a names function called to the function where it's defined or to the exact function and we talked about function signatures now we're going to talk about what exactly assignment means we're going to talk about what is the exact semantics behind this statement of not minus x equals y but x equals y so alright I'll let you out in 2 minutes early so when we get back on Wednesday we're going to talk about this and we're going to assign the semantics to the pointer and we'll show you how to do that