 Alright, good morning everyone. Thanks for coming today in this beautifully slightly cold Monday morning. A little bit of housekeeping before we start. I mentioned it on Friday, I'll mention it again today. I'm going to be out of town on Wednesday, so the TA is going to lead the, lead a discussion section during class, and he'll pass back midterm, so you get your midterms back. You can ask questions about midterms, questions about the projects, questions about really whatever you want. And I'll be posting a lecture for you to watch online, probably today or tomorrow. So I'll send that out to everyone. So I've seen the midterm grades. I was actually pretty impressed. Which may be bad for you, I don't know. If you do too good as a group on the first midterm, that means I need to make the rest of them. Easy. When you say nice, like you're like, oh wow, that's actually really nice. Not like I have never had a class score this low. Yeah, but then I have to think of why. Why is it? Because it was too easy, or is it because you all studied really hard? Studied only bad for a crack dancer. Where did that came from? I'm just teaching. And we're on to now semantics. Some of you remind us, what is semantics? Is it how you win arguments with people? I say, well, actually, it's semantically, technically it means. It's a really good way to know how you make sense of your syntax. So the syntax just tells us what does it look like to be a valid program? Structure. Yeah, exactly. With the context-free grammar. We actually know how to define that. But semantics gets deeper and it gets into the meaning. What does the thing actually mean? So how did you learn Java or C++ or C? Guided. Guided? How did you get guided? Teachers, Stack Overflow. All the semantics of a language available on Stack Overflow. Various coded questions. So one way is like English, right? So you read something or somebody taught you or explained something to you in English, right? They said, okay, this is what it is. This is what a function call is. How do they tell you what it means to be a function call? Try to think back to your own education and learning about these things. So what are you doing when you're doing guided guess and check? So who are you guessing and checking with? Do you like go to the teacher and be like, is this a valid program? The compiler. So one way to define the language semantics is to define everything in English. Another way is basically creating an implementation of either a compiler or an interpreter. And say whatever this accepts is a valid, whatever this accepts and whatever this does is a valid, let's say Ruby program. Because Ruby, I think still kind of is this way. Where the official Ruby interpreter, whatever that does is what an actual Ruby program is supposed to do given that input. And what it doesn't do is not what it's supposed to do. What else? Are there any other ways? So you can do it in English. I could give you a compiler and say this is, this defines the language as semantics. You could look at already existing code. You could look at already existing code. Yes, you could learn by kind of an example, I guess. That could be kind of in the, I guess that's kind of a mix between the two, right? But what's, so what's the problem with English specifications? Yeah, they could be ambiguous. English, right? So you basically, we'll see an example. You basically have to write your semantics like a legal document, right? Covering every possible use case. And then it becomes a little bit more difficult. So you have some ambiguity. Another way we could define a language semantics without any minimizing ambiguity. So what's something else besides English that's not? Mathematically? That's not a different language. Yeah. Mathematically, right? We can formally model and say, hey, look, this is exactly what a function call is and does. These are the semantics of a function call. This is semantics of addition. This is the semantics of dereference. So for English specifications, so if you wanted to learn the C99 programming language, that specification is 538 pages long. Exactly, yeah. It's not even thinking about C versus C++, right? It's not even half. You have no objects, no templates, nothing complicated. I think this is one of the smallest ones. Yeah. That's why I like to show it as an example, right? Because the smallest language still has a huge specification, right? And it has to include things. This is what I mean, you know, lawyer-ese or legal-ese, right, in programming terms. We're saying an identifier can denote an object, a function, a tag, or a member of a structured union or a enumeration, a type def name, a label name, a macro name, or a macro parameter. The same identifier can denote different entities at different points in the program. A member of an enumeration is called an enumeration constant. Macronames and macro parameters are not considered further here, because prior to the semantic phase of program translation, any occurrences of macro names in the source file are replaced by the pre-processing token sequences that constitute their macro definitions. So what is this defining? An identifier, the ID thing that we specified with the regular expression, that was incredibly simple. This is what it means, and this is telling you exactly what an identifier means. But from this, you can know everything, you know exactly where you can use an identifier, right? You can use it to denote objects, functions, tags, members of structures, unions, or enumeration, right, the fields in a structure, type def name, and then it specifically calls out here that, hey, by the way, macros are done by the pre-processor, so it's actually completely before this step. So what's the pros and cons here? Just think about it kind of critically. Wordy, I was going to say, where does that fall under? It's a con, do you agree? Right, yes, you have to, so with wordiness, I guess wordiness by itself is not really a crime. The real crime is that it's hard to understand as the programmer. It's an excerpt of 538. Yeah, this just continues very similarly, in a different way, right, but it has to be very precise, right? Because otherwise, if the compiler doesn't implement something correctly, but you the programmer interpreted it in a different way, you think, oh, I can use an identifier in some other way that's maybe not specified here. What are some other problems with specifications? So if I give you this C document, this 538 page document, you read it all, do you just start writing C code? No. No, why not? Why not? Has anybody ever just read the book and then just like, all right, I don't know how to program C. So you know how Steve Wozniak got really good at designing chips, right? He would, like during school, in school, he would design like a chip or a CPU completely on paper. Because he didn't have the parts. He didn't have money to buy the parts, so he'd design everything and he'd keep doing it over and over, and do the same thing with using less parts. So he would do it all on pen and paper with the specifications of what each component did. Is it possible? Yes. But what are some of the pitfalls? For those of us that have tried to write a complete program and then run it right away. It doesn't necessarily, this tells you, the specifications tells you everything that it does do, but it doesn't necessarily preclude what it shouldn't do, or how to avoid errors or bugs or segfals. You can't verify. Verify what? The correctness of whose code. Of whose code? Your code. My code, right? Okay, yeah, a lot of good points in there, right? So one point is that, hey, look, the spec itself may not be complete, right? It may not specify every case. Not only with semantics, it has to specify what it does and what things do, but it should also include what things shouldn't happen, right, which things are not allowed. In addition, how do you verify that the code you wrote actually conforms to the specification, right? Can you actually approve that? But what about our code? What about other things conforming to specification? So what else has to conform to the specification? If I just throw you a C compiler and be like, use this compiler? No, the compiler has to be known to conform with the specification. The compiler can't do a whole lot with this. So we have these two sides, right? It's me and my code. I'm trying to write my code to the spec. But then I have a compiler who should have been written to the spec. But there's no guarantees on either side that this is actually the case, right? That this code, that both people are correctly implementing the specification. Why is that? Because we're horrible people. Basically. Yeah, there's gonna be different versions and it goes back to the ambiguity, right? The compiler writer may interpret one clause in this whole document one way and I may interpret it another way. It could be that they just ignore it. Maybe the specification is just English. How easy is it to write English? It's pretty easy compared to building a compiler that actually works, right? So maybe they say, hey, whenever you call this function you're gonna get a litter of puppies. The compiler writers go, no, I can't do that. So I'm going to ignore this part of the specification. But now you, the programmer, have to know which parts of puppies that are not implemented and which things are actually implemented, right? So we talk about this. What about cases that the specification doesn't mention, right? Cases where the spec is incomplete. So what is the purpose? So it has all these drawbacks, right? What's the point of having this English specification document? Described and we'll get a general description of what it does without actually getting into the function. Yeah, exactly. Yeah, so hopefully this 538 page document is a little bit more abstract and easier to understand than the code of GCC, right? So that would be one thing. In addition to that, right? So we have the C language. How many C compilers are there? Watts, at least three or four, right? GCC, Clang, the Visual Studio C compiler. There's probably more, Portland and all these other ones, right? So how can we all even agree on what is C and what are the semantics of C? So to be able to write portable programs that we can take and run in any implementation of this specification, right? This is why having a spec is a good thing or can be a good thing. Okay, so I'll reference implementation. So the idea here is I give you code. I give you a compiler and interpreter and I say whatever this code does, that's what the C language is. Whatever you give this as input to this, whatever it does, that's what the C language is. So for instance, I mentioned Ruby, right? Up until all the way up to 2011. Has anybody know when Ruby on Rails first came out? Long time ago. I remember first programming in 1.0 or 0.1 or whatever it was. About 2006, 2005, 2006. So Ruby was starting to become a popular language but it still didn't have an official specification that you can go read and say, hey, this is how Ruby is implemented. What it has was it had an interpreter called the MRI and that defined what was Ruby. Whatever that happened when you ran a code on that interpreter, that's what Ruby was and did. So what is some of the good things about that? Is it good? Is it bad? I feel like that's just as ambiguous as English. Just as ambiguous as English? In what sense? It doesn't really define what can go into it. It's basically just trial and error. If it goes in, it comes out, it works. It doesn't then try again. Right, so there's two sides of that coin, right? So on one hand, hey, I know if I execute this program on this interpreter, whatever that output is, that's a valid Ruby behavior. So in some sense, if you think about it, it's precisely specified. The semantics are precisely specified given a specific input. So this kind of goes back to the guess and test. So if we give it something, then we can figure out what it is. But the flip side of that is, well, what about all those other cases that I didn't test? How can I get an understanding of the actual language? So how are you going to answer that question? What do you do on XYZ or what are the semantics of ABC? How do you solve that with this? Yeah, you try it, right? That's the only way. You have to create a program, and you have to run that test program on sample implementation and see what it does. Right? What are some of the downsides? Is this, like, perfect? We already talked about this, right? So it's precisely specified. What about other... If you don't know where to start, them telling you that, oh, whatever the interpreter does is the right thing, doesn't even get you in the ballpark. Yeah, I mean, just by itself, your reference implementation is basically useless because what are you going to do? Yes, I mean, okay, you do have the grammar, so you can generate all possible programs, right, in that language, but still, you're not going to be able to run them all. And what do they mean? Like, how do you interpret those results? What else? So we talked about correctness in English specifications. Does this have a correctness problem? Because there's no written specification for the interpreter, it's hard to know if whoever wrote the interpreter made an error, or if that's really what it's really supposed to do. So what if they do? What if they make an error? What if there's a bug in the implementation? Well, their statement here is that, yeah, that's exactly what it's supposed to do. And that's exactly what happens, right? They actually, bugs become part of the language because applications have already been written taking advantage of this behavior. And so those bugs persist in the language itself. This is maybe doing web programming stuff. There's so much crazy hacks and like CSS and JavaScript and all that. It's because of this, right? They become de facto parts of the standard that everybody has to support. So what about portability? Does this affect portability at all? Using a reference implementation? Well, regardless of where it is, whatever input goes into it, yeah, it puts its value. Correct. So what about, so with English specification, right, we can count on, hey, multiple implementations of that specification, right? What if you're running a MIPS machine and Max never tested his interpreter on MIPS, right? So yeah, what if your implementation doesn't run on your platform? You're just screwed. You'll never know if that's available. You literally can't execute the interpreter, so you can't understand what is a Ruby program on that machine. So formal specifications, right? So here we're going to actually say, okay, let's deal with the problems of English, and we'll say, hey, English is a terrible language to describe a specification in because it's very ambiguous. So let's use math and let's describe things formally. So what are some of the benefits here? Does anybody learn a language like this? Not a functional one? What language did you learn like this? Cool. Any programming language? So what are some of the benefits? What are some of the pros and cons? The pros is that if you do actually spend the time to read it and digest it and actually understand it, you do have a better grasp of it than you would get through any other way. Right. The cons are just the sheer amount of time that it would take to do that. Yeah, right. So if the language is formally defined, unlike English, is that going to leave cases that are maybe not specified or... So it should be the case that all parts of the language have an exact and precise definition, right? So there's never any doubt. You should be able to, from the formal specification, understand what does it mean in this specific context? What happens if I do take a dereference and then take an address and then access a field and then take the dereference of that, right? What are some other benefits? So if we have this all in math, essentially, or we have some kind of formalism, what does that allow us to do then? Proofs. Yeah, right? We can actually try to prove things about programs written in this language, right? And actually, that's where a lot of the work in formal specifications comes from and that's where I've been exposed to it. It's not so much that you do this, well, they don't really do this with the intent of how to program the language like this. They do this so that we can statically analyze the code to try to understand what it could do to try to detect vulnerabilities. So the downside, pretty difficult to understand. So if you don't believe that, here's a snippet of formal semantics defined using a technique called abstract interpretation of JavaScript. Anybody think they know JavaScript? So actually, this is one of those things that, of course, I show this up here and it's meant to be complicated. But actually, when you break this down and you take each thing piece by piece and you understand exactly what each column is doing, it actually is straightforward and precise and it says things like basically how to handle its statements. So basically, you evaluate the expression if it's true, then the next thing you're going to execute is the true branch. Otherwise, the next thing that's going to be executed is the true branch, always here. So basically, it abstractly represents the machine and then specifies how the machine execution state changes as it goes through. So this is from one of my, one of the professors at UC Santa Barbara who I borrowed this from. I did not come up with this. But yeah, it shows how to do everything. Assignment, delete, defining new functions, wall loops, everything. The language can be specified this way. But I would agree with you that it's a little bit obtuse. You kind of have to already know the language to understand what this means and what it represents. Okay. So now that we've seen kind of how to define semantics, we've seen different ways of doing that. What things need to be specified? What do semantics actually need to define? When you think about your own self, when you go to a programming language, what are the things you want to know about this language? Controls are in one sense. Like how they're other constructed in terms of we have a diff statement, we have to have a diff followed by a set of parentheses, and inside those parentheses we have some sort of statement. So we need to know, we need to have a semantics to define that word means something. Yes. Right. It would mean that, hey, when we get to this point of the program's execution, evaluating expression that's within parentheses, if that expression evaluates to true, then execute inside the branch, otherwise go outside. I mean, what about telling if something's true? Is that part of the semantics? Is true the same in every language? No. No, right? It's a lot different. PHP is like the worst example of things being true or not. I think you take the string containing a zero is equal to false. You compare that because it automatically tries to cast the string containing zero to an integer, and then zero, the integer is equal to false in PHP, which is insane. Right? Some things have literal true and false. In C, what's true and what's false? Right. Zero is false, but everything else is true, which is also kind of weird, right? It's not quite as explicit as you'd want. But all of these things, right? They get into these, for you to actually program in this language, you have to know this. In some languages like Lisp, the empty list is considered false. It's not actually, I mean, it's not false, but if you say if something and it's an empty list, then it won't execute that instruction. So you need to know these things. What are these? So we have if statements, conditionals, loops, while statements. What's the difference between a while and a do-while? But you have to know this, right? It's not obvious. You have to learn this. This is part of your understanding of the language. Could you think of other control structures? Switch statements. Switch statements? How do switch statements work? Lisp actually has an unless statement, which is like an if statement but opposite. So unless this thing is true, execute this code branch. Sometimes it can make the code a lot more easier to read. What are some other things? So those are all the control structures. Is that all you need? If you declare variables, you need to know where you can expect to be able to access them. What does it even mean to declare a variable, right? You have to go all the way down to the bottom. That's why these things have to be so long, right? What does it mean to declare a variable? In some languages like Python, you don't need to declare variables, right? They just pop into existence whenever you use them, right? But then when we get into defining variables, right, where can it be used to refer to that variable's declaration? So scoping rules. What are the scoping rules? What are the things? Say that again? Types. Types. What about types? Everything about types, right? Types are its own semantic section, right? So what are the basic types? How does the programmer construct new types? Whenever you create a structure with different fields, right, you're actually constructing a new type. What does it mean? When can two types be equal to each other, right? When can we transfer from one to the other, or when do we have to explicitly cast it? What does it mean to explicitly cast? What if we mess up a cast? What if we say that something is a dog when really it's a... Is the programmer going to stop or is it going to keep going? Apple's probably not going to park. Anything else? What does the apple have to do with that part? It depends on if it has the method or not. Memory? Can we even access direct raw memory, right? In C, we can do that in other languages we can't. What about functions? Is there anything important about functions, or are they just super obvious when you first learned about them? What does it output? How many parameters does it have? How do I get the return value? How many parameters does it have? How do I call it? What are the types of those parameters? Can the calling function modify any of the parameters, right? In the call ease environment? All kinds of stuff, right? We talk about variables, functions, parameters, types. What about operators? What does it mean when you do ID plus ID? On most languages it's addition. Sometimes. Unless it's string concatenation. So how do you know? Some languages like PHP have to use the stupid dot operator to concatenate strings. It becomes really annoying. And you also have in C, you're supposed to get an operator overloading. Yeah. You don't have operator overloading in C, but in C plus plus you do. So yeah. You can, yes, you can overload operators. And if you do any Haskell stuff, you'll see that people overload operators like crazy, which makes it very difficult to understand what's going on. What happens when there's a problem in your code? Does your code always run smoothly 100% of the time? Sure. Yes. Yes. For all these notes. So what happens when an error occurs? Right in the corner. Right in the corner. Hopefully your program doesn't do that. Stack overflow? How do you know that a stack overflow occurred? How do you know that it occurred? Oh, oh, you're saying you use stack overflow. I was saying an actual stack overflow. I'm going to complain to them. Typically your environment will give you some feedback. Once compiler tells you, hey, idiot, you messed up here. What about a runtime error? Then you have to rely on your operating system and your debugger. Kind of. Your program will raise an exception. Yeah, right. Exceptions. So what are the semantics behind exceptions? Can you, you know, do you have to, like in Java, do you have to catch every possible exception of a method that's called? Every method, every function has to declare exactly what it can throw in, or in C or C++, how are exceptions handled, right? They're actually handled very differently. In languages like Lisp, there actually, the exception handling system is completely different. You can actually catch an exception of the stack, change things, and then re-execute whatever you were executing. You can just go back and continue executing there. It's actually really crazy. Huh? Yes. That's cool. Yeah. It's actually really, they have a lot of really cool stuff. Control structures we talked about? What about constants? This would be pretty trivial, right? But what does it mean for something to be constant? Always accessible. Always accessible unless the flip side of that? Unchanging. And unchanging, right? So it means that you can't assign to something that's constant. You can't change something that's constant. Does the language actually enforce this or not? Something you need to know, right? Methods, classes. We didn't even talk to get into object orientation, right? But you'd think that's a whole other set of semantics. What does it mean with classes? Can I inherit from multiple classes? What happens when I inherit in C++ for multiple classes and they have the same method with the same signatures? How do I even define the same method? That's kind of a fundamental question. So semantics is really about trying to answer all these questions and define what does a language actually do? So it's something I want you to think about because I think these things, we kind of take them for granted after we learn them. We're like, oh, of course, method calls work this way. Or of course, operator overloading happens like this. But really, this is just the particularities of your specific programming language. So what we're going to do now, we're going to dive into several different types of semantics to try to understand that. So there's a few things that are important here. A, that semantics are essentially arbitrary. You as the language designer, you can define your semantics however you want. You don't have to have function calls. They don't have to be function calls. You can do it kind of however you want. So we're going to look at different types of semantics so that we can understand, in some sense, the design space and in another sense, to understand that these aren't handed down by programming gods that came to us and said, this is how our shelves program computers, right? These are like humans coming up with these things. Okay, so what are declarations? Defining something, why? Why do we want to define things? So we can use them, right? So we can use them, yeah, right? So do we always have to declare everything? Depends on the language. Depends on the language, right? So yeah, so sometimes for some, I'm using kind of an abstract term, constructs here, so some kind of language constructs. Before we actually use them, we need to explicitly declare, hey, I'm going to use a variable that's type is an integer and the name of that variable is foo, right? So we can give it a specific name, right? So this would be an integer whose name is i. We have declared, do we always have to do this? What's the difference between explicit and implicit declarations? Something like every time a program starts, there's just something i in this instance or something. Yeah, right? So it could be, yeah, so implicit could be two things, actually, that's a good point. One thing could be the language actually defines a variable. I think in some languages, if you do like a for loop, it automatically creates an i variable or an iterator variable or an index variable. I'm not 100% certain. But other things like in Python, right, I don't have to declare anything, right? I'm going to say target is equal to test value plus 10. And while it's interpreting this, it'll see target and it'll go, okay, great, this must be a new variable named target. What are some of the pros and cons of these approaches? You can do one variable and accidentally mess type if you just made new variable. Yes, it's a huge problem in Python, right? If I forgot the R in target, it was just target, right? I won't know later on. Later on, maybe I'll get an undefined variable, but maybe not, right? Maybe the program still executes because target was actually defined earlier. And when I use it again later, it's using the old value that didn't get updated with this test value, right? What about the downsides? Is it soup? Yeah. You know what test value is as well and you know that it's supposed to be so. Yeah, it's kind of hard to see if you're just looking at this code. It's not really clear. Is target supposed to be declared here? Is it not? Is it something else? What about the other way? What are some of the drawbacks of explicit? Yeah. It's very rigid and you have to, okay, I'm going to have these integers, all of my variables first, and now I'm going to go do something with them. Right, yeah, it all seems kind of backwards in some sense. At least it feels that way to me when I'm programming like in C and I have to put all the decorations at the top of a block or a method, right? It's like, well, I don't actually, while I'm writing it, I don't know precisely every variable I'm going to need, right? So I kind of actually do it in more of an implicit style and then go back and put in the decorations that I need, right? So definitely some trade-offs. What else can be, I don't know, kind of nice about explicit declarations? Anything else? Because it's explicit, you always know where it's defined, what it's going to be called, maybe what it was originally initialized to. Yeah, and we can tell that, right? So we can tell by looking at this, but who else, what else can tell? Anyone else that looks at our code? Anyone else that looks at our code? Okay, good, yes? Yeah, it actually does increase the, in some sense, the documentation, right? You're declaring, okay, these are the variables I'm going to use and then later on you can see how they're used. What about the compiler? Actually, I believe, I don't know that I have proof of this, but I suspect that in C, the reason why you have to do this at the beginning, so the compiler can easily go through and see for every function or block exactly what variables are being used, what's their type, what's their size, so it can allocate space correctly for them. It actually makes the compiler's job a lot easier, right? So even if implicit declarations were great for programmers, and they are and they have benefits, right? This is actually better for the compiler writer, so if I control the spec, I'll be like, yeah, we're definitely doing this. It's a lot easier. So we can declare things like this, so part of this declaration, what kind of, what are some concepts that are involved in here that we haven't covered that probably have their own semantic definitions? How types work? How types work? Assign it just the first layer. How mathematics, how the mathematics and adding some tri-thing, et cetera, work? That actually is a good point. Just this line, though. That is something we'll have to get into. The terminating character, like for C and Java it's the semicolon, but for some other language in which it could be pound or at. So terminating character, that's more syntax. At this point we don't really care. All we know is we have a declaration here, and we know that a declaration is a type followed by what? An identifier. An identifier, right? So how do we know? So we say a specific name, right? But how do names work? Is it obvious when you started programming you were like, I know how to refer to variables and functions and the difference between the two? Well, there are some things that are illegal to, for languages, they're illegal identifiers. Yeah, right? So like, what is this name mean? When I declare a variable i, so long in some sense, how long is that declaration valid, right? Where else in the program can I use that variable i to refer to that thing? So what are some of the possibilities? Based on scope, yeah. Based on scope, what are some of the ways you could do it? Globally, right? So it could be that when I declare something it's available for the entire program, right? And when I'm saying entire program, I mean the entire program, right? Any part of the program can access that variable and that name. What else? Locally? Once you leave the function that it's declared in. Yeah, so locally in the function or something like that? Just inside of a loop. Just inside, like maybe just where it's actually used. What about just the file, right? Just that variable is only allowed to be used within this one file, which kind of breaks it down a little bit in an entire program. What about global? What would that mean? Everything that this particular program would need to access or could access? More global than that. Like other programs? Yeah, right? Could you make it so that you declare variables that are global across all programs that are ever written in that language? It'd be kind of cool to think about, right? Wasn't that like some of the predefined constants and names already in the language? Yeah, right? Or how does Android do package names? How do you uniquely identify an Android app? Yeah, it's like the package name, right? It's com.something.something. That something has to be globally unique, right? And that's how Google identifies that this is your app and that you wrote this app. And in the package manifest, it has that specific string and that's how the OS knows, okay, this package really doesn't belong to this package name. So it seems like a crazy idea to do this, like, globally across all possible programs. But actually, you know, you can think about that. And it'd be really cool to think about, like, I've heard some things of you can basically essentially make all functions in the language that anybody writes globally accessible. So you could just kind of like publish them out on something so you could call anybody's function and it would pull down that code and actually execute it and do whatever it's supposed to do. I think it entered their code intense. Something different. Intense are a way to do basically remote procedure calls. No, this would be like programming in some new language, like Java, right? And instead of when you want to use a library, you have to download the JAR file and include it in your source code. You just call that function and that function itself has a globally unique name. So the Java interpreter would know to go pull down that specific function from that file. You get some very unique names. Yeah, right? That's the big problem with this, is how do you make... So this is why... This is why in Java and on Android you use basically reverse domain name. That's kind of the idea here. Okay, we talked about like function, right? So this is about... Kind of what we're looking at here, right, is how long... So when we declare something, when we declare a name, how long is it valid for? What's the flip side to that? So this is saying... Okay, if I declare something here, it's valid for a certain length of time or length of program execution or some part of the lexical scope of the program. Right? What's the flip side to that? You can't reuse it? Is that something different? Maybe, depending on the semantics. That's part of semantics, is can you declare something else? Right? So the flip side is, what happens when you see an identifier? What are you trying to do? What are you trying to do when it sees an identifier? When it sees ID plus ID? The substitute probably does a type check, see if they can be added, then if they can't, it adds them if they can, but it adds what? Keep saying that. Whatever it is. It tries to associate the identifier with a location that holds the value that you want to perform the operation. More abstractly than location, right? Really just the declaration. So the idea is exactly... So as the program is going through, in order to do type checking, in order to actually perform this operation, right? How do we map a name, an ID that we see in the program, to a declaration? Right? Every see how these are kind of two sides of the same coin? Yeah. In one side we're saying, okay, when we declare something, how long is it valid? And the other way is, when I see an ID, how do I map that back to the declaration? And so scope, right? So scope essentially tries to define these two questions of how long is a declaration valid and how to resolve a name. So is scope being simple? No. No, said somebody with too much personal experience with it. Anybody ever get in trouble with scope being rules? Right? Gets even a little bit crazier with object-oriented languages because you have, not only do you have scope, but then you have public, private, internal friend on all the fields and I have visibility issues too. So what are the see scope being rules? What is, so when we talk about scope being rules, we like to talk about this, usually we like to talk about this concept of how long are things valid for, right? So for instance we talked about is every declaration global, you know, global? Or is every declaration whole program? Or is every declaration whole file? Or what's kind of the most basic level that declarations have in C? Locally on the stack, more abstract about that, we're not even thinking about stack and everything. Just within a code block. There you go. So C uses block level scoping. So some languages do block level scoping, which means that things are available in a block. What's a block in C? Curly braces. Curly braces. Do you have to have if statements, function definitions do you have curly braces? No. No. How would you know that? Try it. If you didn't just try it or have one of your fellow classmates just try it, how would you find that out? What specifications specifically are you going to look at in C? The grammar. The grammar will tell you where those braces are valid, right? And then the semantics say what that means, right? Curly braces don't mean anything. It doesn't matter where they could go, right? But specifically here in C you can create a block anywhere without a function definition, without an if statement. And so what does this mean when we say it has like block level scoping? What is available with that? So it answers that first question, right? So anything defined in that block is only available inside that block, right? What about declarations that aren't in a block? Program. Program? Yeah. So I put global here, but yeah, from the way we were talking about earlier, right? So if you declare something that's not in a block, it's global, unless you use the static keyword. If you use the static keyword on a global declaration in C, it means that declaration is valid only in that file. Why would that be useful? For that particular piece of data to be only be usable in that file outside of it. Yeah, it's primitive information hiding, right? You're essentially saying, I want this global variable, but I want it private to this function, right? I don't, or not this function, private to this file. I don't want other files to be able to include this to be able to access this global variable, right? So in some sense, it's a way to do private global variables, but it's a little bit weird because it's on the file level, right? Not a class level or anything like that. So what about JavaScript? Somebody who's familiar with JavaScript, what's JavaScript's scoping level? I saw some hand raised for JavaScript programmers. That was a test. What was it? It's nonsense. It's nonsense? It's absolutely crazy. It is crazy. But it has actually a well-defined, well-defined scoping rules, which once you, hopefully when you understand the scoping rules, you understand how JavaScript works, it makes concepts a lot easier in my mind. Maybe I also want to take a stab. Is it global? Global? No. That would be crazy. A little. Okay. Not really. A little bit. It actually uses function-level scoping. So this means that the braces don't matter, but anything defined, any variable defined within a function can be accessible within that function. So it seems reasonable, except for the fact that sometimes, if you define a variable inside an if statement, if you think in C, that variable is not accessible outside that if statement, it's not true in JavaScript. You can actually access that. This is actually why, how people do namespacing in JavaScript. If you want to create your own little scope, you have to actually define a function, and then immediately call that function, and that has the effect of using curly braces. All right. Let's look at an example. So here we have a C program, include standard.io.h. We have our main function. So here we're defining a scope. With the curly braces, we have a block where we're defining a scope. We have a smaller block within it. We have an int i. i is equal to 10,000. Print out i. Then another block. Print out i. So where is this i valid? And how do we know? In this block. Which block? How many blocks are there in this? There's three blocks in the first inner block. There's actually two inner blocks. So everybody see how these blocks have a hierarchy? We have the outer block, and then we have two inner blocks here. This is totally valid in C code. You can compile this. Well, you can compile it. Wouldn't it say that the second i is not valid in that scope? This i? This i? The one in the second block. This i? Yeah. Yeah, so what's the problem here? It's not declared. It's not declared. I declared it right here. But that's only in that block. So what's going to happen when we try to compile this? It's going to say that... Why is it important that we try to understand what the code's going to do before we compile it? So we can make sense of what the compiler tells us. Yeah, so a. So a couple of reasons, right? So one is you really, I mean this part of growing as a developer, programmer, computer scientist, right? You want to be able to look at code and reason about what it's going to do without actually running it through the compiler, right? It's very easy to do self-guided test and check, right? But really, we want to be able to, like you need to, and I say this not just because in a general computer science-y type way, but because on exams, you're going to be giving snippets of code and saying like, I'm going to output if it has these level scoping rules or it uses static scoping or dynamic scoping or all these different types of things, right? So you need to be able to look at code, be able to step through it and know exactly what it's going to do without actually running it, right? And this helps you reason about the code. So really also the goal is you want to look at this kind of like a scientist, right? This is how I approach debugging, too. It's like, okay, before doing this, what do I expect this program to output based on my knowledge of C and my understanding of the semantics of C? What do I expect this combination to output? So do we expect this to work? No. No. What do we expect the error message to be on which, yeah? The second I. The second block. Fourth I. Yeah. One, two, three, four. Yes. Right? This I? Yeah. So after we compile this, we're first using this function, right? And we see 11, one, two, three, four, five, six, seven, eight, nine, 10, 11, because there's an extra space somewhere. So this is good. So this actually now we were able to look at the code. We were able to verify that it actually did throw an error after we ran it, right? And so where this is really important is if we look at this and we say, yeah, this should be fine. It should output 10,000 and then output 10,000, right? If we do that and then we run it and go, oh, wow, weird. There's an error. Then you know there's something wrong with your understanding of the semantics and the execution, and you need to go fix that in your brain, basically, and change the way you're thinking about code so that that way you can predict these things. Cool. So where is this I valid? Yeah. Just these three lines, right? And so when we see this I, right? So now in the process, we need to go in the reverse. So we see this declaration. We look at this I, and we're trying to map it to this declaration, and we see this I, we map it to this declaration, but when we see this I, there's no declaration to map it to, right? So that is at the basic level for a language like C and Java. This is what happens when you get an undeclared identifier, right? It saw an ID, it tried to map it to a declaration, and it couldn't.