So it looks like a lot longer. The site is with a truck across the street, but. All right, cool. All right, so we are talking about, so we've looked at dangling references, and we're looking at memory errors and semantic errors. And so we looked at dangling references, and we saw that this code, right, the value of what this dang variable points to actually changes, and it changes depending on actually the system that we're using. So we'll see kind of why that is later, because it is pretty cool. So let's look at a different example. So here we have our main program again. We have a local variable called dang, a local variable called foo. All right, so what are the variables that are gonna be, so where are dang and foo allocated? So dang is gonna be on the stack and foo. Cool, and how do we know that? They're local variables of function main, right? So all local variables are stored on the stack. Awesome, and then we're allocating, we're calling malloc to allocate a new integer, right? So now, so what is malloc going to do? Allocate memory on the heap. Yeah, so it's gonna be a heap allocation for us, right? It's gonna create a new location on the heap. The return value of malloc is gonna be the address of this new location, and we're gonna copy that address and put it into the value inside the location associated with the dang, which is on the stack. So that's gonna be copied in there. Then we're gonna set foo equal to dang. We can do that. So what's this gonna do? What are the semantics of this statement going to be? Sorry. It's gonna copy the value associated with location dang into the location associated with foo. Yes, so copy the value in the location associated with dang to the value in the location associated with foo, right? So what's inside dang right now? What's that value inside dang? The address. The address at, which address? The address that malloc returned. Yes, the address that malloc returned, right? So we're copying that address and copying it into the value associated with foo, and then we're gonna set star foo equals to 100. So what is star foo reference? Don't help the address. What is the star, what is the dereference operator that always returned? L value or R value? What's that? An L value or an R value? You're all the different types of answers. Actually, I've figured three answers. L, so who says it's an L value? Who says it's an R value? Well, how can you tell just from the, so A, is this assignment statement valid? Yes. Yes. So if this assignment statement is semantically valid, what does that mean? Can you have an R value equals an R value? Can you ever have an R value on the left-hand side of an equation? No. Is this where L value gets its name from? Yes. Yes, left. You can only use it on the left side of an assignment statement. So star foo returns an L value, right? Which is a location, right? So dereferences always return the location, not the value, right? How you use that location, maybe how you use it, you get the value from that, right? So here we're taking 100 and where are we storing 100? In the location associated with star foo. And so star foo is taking the address inside foo and finding the box that's associated with that. And so that's that location. So we're copying 100, the R value 100, and putting it in there. In the address of foo. In the address of foo. No. In where foo points to. Using the value inside foo, find a location that has that address, which is going to be the thing that was returned by malloc. And then copy 100 into there. So let me free foo. So what does the free function do? Yeah, the allocates the memory, right? So it's going to look up foo and it's going to say, OK, whatever the address is inside foo, this box now goes away. It's no longer valid. So then what happens to dang? What's the value inside the location associated with dang? The same address. The same address, which is the address returned by foo. So what happens when we print out this dereference? You should get an error. Should get an error. We want it to get an error. So yeah, the address inside dang no longer has been allocated, right? It's been explicitly deallocated through foo. So after this line, what are foo and dang? After this line, right? Before the free. At this line. What was that? Aliases. Aliases, yeah, they're aliases, right? They both refer to the same box, right? foo and dang are two different ways to reference that same box, which was the return of malloc. So when we use one of them, like foo, to free that, now when we try to dereference dang, right? Now, dang is now pointing to a box that doesn't exist. And so, but anyone guess what it's going to print out? Zero, three, well, 100. All right, it's going to print out maybe something and assuming it continues, then we can malloc. So now we're going to malloc a new, right? So malloc is going to create a new box for us and the address of that box it's going to put into foo. And then we're going to set that newly malloc location. We're going to set that equal to 42. And then we're going to free foo. And we're going to print out dang again. So what's dang going to output? What's this program going to output? Could output 42? It could still output 100. It could also still output 100? Yeah, let's see, right? But one of the keys is there's a dangling reference, right? Dang is a dangling reference. So really the output here is, could be anything, exactly. So we can compile this and actually this program will, on our version of GCC, will not give you any warnings when you compile it. It will completely work 100% fine. Then when we run this, so it's going to first output zero and then output zero again, interesting. So that's on GCC. And then on the Mac, compiling this gives no errors. Running this outputs 10 and 142. It's actually kind of interesting because it depends on the exact allocation library that you're using and what it's doing. But here we can see that it's actually, when you, the second called malloc, what's the address that gets returned here? The original. The same as the one that was freed, yeah, in the original malloc, right? Because that's the value, the value of the original malloc is what's inside dang. And so the call this second malloc actually returns the same address, right? And so we get really crazy results here from these dangling references. Let's look at one more example. So we're here in main and then we enter a new scope, right, scoping rules. So inside the main scope of main, there's an int pointer a declared. And then inside that scope, we have an int star b declared. And then we are malloc and new integer assigning it to a, right? Mallocing another new integer, assigning it to b. So this means that we can call these addresses address one and address two. So that's what we're going for here. Then we dereference a, so we set the value inside the box that the first at memory one, we're setting that to be 42. Then we are mallocing a new integer and setting it to b. And then we set star b is equal to star a. So what's this going to do? B gets the address of, gets the value. B's pointing to a's address. B's getting the value. B gets the value of a. So what's going to be inside the box b? 42 address. An address, yeah, that's a good question. Three, three's going to be inside b. So what's going to be inside the box three? 42. 42, right? So it's going to dereference a, which is going to look at memory address one, the box associated with memory address one. It's going to grab that value in there, 42, but it's going to copy it to memory address three. Then we say q.  We're going to say q is equal to the address of a. So whatever the address of a is, we're going to copy it into q. So what kind of memory problems do we have at this point? What kind of semantic? A leak. Do we have a leak? Or what else have we been calling that? Garbage, yeah, we have garbage. So which memory address is garbage at this point? Memory two. Memory two, right? So we've allocated memory two with absolutely no way using the variables that we have in scope at this point that we can reference memory two, right? Because a has memory address one and q has the address of a. Then when we get out of here, so what happens here when we leave this scope? So you go out of scope, you can't access any of that memory. Correct, so what happens to the variables? Like how does the, what changes memory-wise or allocation-wise? The one you deallocated. What would be? B. B, yeah, so because we're leaving the scope, B is automatically, so B is stack allocated, right? So after we leave this scope, B is automatically deallocated. Memories one, two, and three are not, right? Because they're keep allocated, yeah. Why? So using the variables at this point, so what variables do we have at this point? A, B, N, A star, B star. At the very top, Q, right? We have Q, A, and B. So using Q, A, and B and D references, can you ever reach memory two? No, even before, right here, right? So what's inside B, right? The value three, which is the address three. And what's inside A? One, right from this. One is gonna be inside A. Three's inside B. At this point, Q has the address of A, right? So if you dereference Q, you'll get to A. If you dereference A, you'll get to memory address one. If you take B, you dereference B, you get to memory address three. Recent, most recent memory for B is memory three. Like, most recent declaration. Exactly, at this point, right? At point one, there is no garbage, right? We can access both memory one and memory two. But now at this point, actually, at this point right here, we now no longer can access memory two. So at this point, memory two is garbage. So now, what about here? So now we've deallocated, automatically deallocated B. So what are the variables that we have available here? A and Q. A and Q. So then what memory is garbage here? Two and three. Two and three? Yeah, so we can't access two or three here when main ends. Q, Q. Ah, but there is no A anymore. You can access the memory that was associated with a through Q still. So what would that be for Q? What would we call that if we can access a memory address but that memory address is no longer allocated? So at this point, Q would be the dangling reference and we'd still have three garbage memory addresses, one, two, and three. I guess if you assume that this isn't actually main and it's actually was called by something else or something else happens, you can actually in your own program call name again. So main doesn't necessarily have to be the top level function. Okay, cool. So now we looked at memory semantics. Now we're gonna look at assignment semantics. So we've been looking at so far copy semantics, right? Which when we see an assignment statement, we know exactly how to interpret that, right? So when we see A equals B, what does this mean in the semantics that we've been using so far? Longer. What's the value of B? How do we know the value of B? Like in the circle box diagrams. So yeah, we're copying, right? But for being like incredibly precise because we wanted to find the semantics so that everybody knows exactly what we mean. Copy the value of the address in B? B is not an address, B is a variable. It holds the value. It may hold the value again, it's supposed to be. I don't know. They said that we can copy the value of the address of A to the location that holds. Yes, locations, right? We wanna talk about locations. Yeah, no, no, no. The location that holds the value of A to the location that holds the value of B, right? Backward. What's it? That's right. Copy B to A? Oh, okay. Yes, yes. So copy the value in the location associated with B to the value in the location associated with A, right? So very verbose, but that way we know exactly what we mean, right? When we see this copy assignment, this is exactly what we mean. But crazy enough, this isn't, you know, this is one of those things we take for granted because we've been programming for a long time, right? And this is how we do assignment statements, right? But these aren't the only way and really it can help to think about different ways that you could do this. So in some languages you can do what's called cheering semantics, which instead of copying the value, basically means when you have A equals B, instead of copying values, what you're gonna do is change the binding associated with A to now be bound to the location associated with B. So this would be bind the name B to the location associated with A. Sorry, I think I said that backwards. Right, so in this case, you're actually changing the bindings between, right? And the bindings is the arrow between a variable and a box. So I'm actually changing that binding, yeah. Doesn't that just make them aliases? It does, it definitely makes them aliases, yes. Cool, so let's look at this. So let's say we have some object A, right? So this is going to create a variable A and we have some object B and this is gonna create some variable B, right? But in sharing semantics, these don't automatically create a location associated with them until we actually allocate some new memory. So here we're saying, okay, A is now bound to this new object. So we have the new is creating a new object and so now we have a new box and we're binding A to that new box. And on the next line, we're binding B to some new object and then we say A is equal to some new object, right? Instead of copying the address in there and everything, now we're creating, we're gonna create a new box and we're going to bind A to that new box. Then when I said B equals to A in sharing semantics, what's gonna happen? He's now gonna, the arrow between B and a box is gonna move to the box that. Yeah, so this arrow is gonna move here, right? So B and A are gonna both refer to that same object. So does this kinda look familiar? Is this C code? No? Java. Java, yeah. So Java actually has, it's not, it gets a little wonky, but it has a form of sharing semantics, right? Where you, so there's kind of two ways to think about it. The, I don't know, more systems level way, I guess, is to think that, well, in Java, all the objects are actually, that's a pointer to an object, right? And then basically everything, except for primitive values, are pointers. And so when you said B equals to A, you're just changing the pointers. But in Java, you can never actually access the pointers directly. So the other way to think about it is, think about it with sharing semantics here, to say that, okay, when I declare an object A or an object B, I'm just defining a name, that that name has no location yet, until you allocate a new object and assign it there. Questions? Types on lines? Types on types, I don't think so. We haven't got there yet, so it would not be online. Cool. So, do you love type systems?  What are your feelings at this point? They're great until you try to convert from one to the other. They're great until you try to convert from one to the other. Anybody else? Love them, hate them, do you wish they weren't, didn't exist? Maybe not that far. It's just, sometimes it gets very annoying when your elbow deep in someone else's code and you're trying to figure out what the heck needs to be passed to get the whole function to work. Yeah, so it can make using other people's code more difficult. Is there any program in the language that doesn't, all languages have types, right? But, like a language like Python or JavaScript where you don't have to declare types, so do you think it's good, better, worse? What was it? It sucks? It's nice when you use it correctly, but it will allow you to shoot yourself in the foot like you would not do it. Yes, so you can shoot yourself in the foot. Yeah, so what is, what is a type? And why do we use types, sorry. Why do we even, why did somebody create this and why did everybody else think, yeah, this is a good idea. Or why do you think that's a good idea when you're writing, you know, compared to JavaScript or Python, right? You don't have to declare types in advance and the compiler doesn't do any checking of types. But why? Yeah. Like you have two objects you didn't know of. Only want to be able to say one object is the same as another object if they're the same type. So you need some way to identify that they're, they have the same properties that are the same variables and operations. All right. And also, if you have a strongly typed language or you have to declare a type, that can give you more control over how the program works because then you can do stuff like casping. Ooh, casping. And you can sort of like tell the compiler that you know what you're doing, sometimes not. And that also helps as a form of documentation. It will tell the computer how to interpret something. So like if you have a hundred written out in ASCII, it will be three bytes total and it will be interpreted with whatever the ASCII code is for one, zero, and zero. Versus if you have an int, 100, it will be, I don't want to do the math, but one, one, zero, zero, something like that. All right, interesting. Yeah, so, I don't think about it in this way, right? Do type systems allow us to write programs we could never write before? No. Do they allow us to be more expressive and to create better, interesting programs that we could never do before? No. They're actually restrictive. They're actually restrictive, right? Yeah, if you think about it, right? A program, type systems are actually confining you, right? They're limiting the amount of possible programs you can write in that language. And then you may have to fight with that type system by using casting, right? To say, no, no, I know what I'm doing here, type system, trust me. I'm sort of just like to make no sense of what you write because it wouldn't make sense to add five to the letter S. Like, who would do that, yeah, I mean. Yeah, so, there is an amount of productivity that type systems gives you, because we aren't computers and we can't process the raw data like the way, like, yes, if you didn't have a type system, you could create like some kind of Google program that could convert from like a void pointer to like a dump or something ridiculous. But why? Why, yes, why indeed? Yeah, so I think you all are kind of saying very similar things, right? So the type system confines us, right? But it's there to help us also to help, essentially help document our code, right? So that we can say, hey, okay, we know to the computer, right, at the bottom everything is in ones and zeros, right? Which we just had to deal with those ones and zeros to program, it would be a little bit crazy. So we wanna do some abstractions like, hey, even though, so I'm treating this thing as a character, right? Which even though I know the computer is gonna store as ones and zeros, I wanna treat it as if it is an abstract character, right? And so that way I want the compiler to stop me if I ever try to add a character and a double, right? Because that doesn't make sense. So we can think about, so kind of informally, we can say that while a type is some set of values and some operations that can be applied to those values, right, so we can say, okay, an integer is all numbers from, let's go unsigned in, so that's easier. Zero to two to the 32, right? Every number in there could possibly be represented and what are some operations that we can apply on the integer type? Addition, subtraction, multiplication, and division. Yeah, addition, subtraction, and multiplication. And, right, so types exist externally of our program, right, but when we want to use them in our program, we have to somehow associate and communicate this to the compiler, hey, this variable has this type, right, or this constant has this type. And so, right, so these values of types, right, are not necessarily just numeric types, right? We have types for functions. We have a way to specify the type of a function. And so we're gonna be thinking about kind of type, we're gonna be thinking about type systems. So we're gonna be thinking about, okay, what are all the things that go into creating a type system and what are all the different ways we can do this and how does that trade-off affect the programmer and the compiler, right? So every type system has basic types, right? You have to have some building blocks, everything, right? So what is one of the basic types of, like, let's say C. Hit, star, character, float, double, long, Boolean. So then what else do we need, guys? We have the program, as us programmers, can we just use basic types and we say, hey, we've got basic types, we're totally good. It's not convenient. So then the type system would, let's say, more get in your way than, no. More so than it's worth, yeah. More so than it's worth, yeah. So what else do we need beyond the basic types? Structs or objects or something. What are structs and objects? Program or creative types. They're basically custom types. Yes, is that again? Program or creative types. Yeah, so they allow the programmer to construct new types, right? They allow us to say, like, a struct says, hey, I'm gonna create a new type and that type is a combination of two types. The first type is an integer and the second type is a character, right? And so we need some way to allow the programmers to use these basic types to construct new interesting types. And this is really what gets, this is really where a lot of the power comes from, right? Is if we just allow the programmers basic types, if you're way too restricting, right?  I don't wanna use this. But if we allow the programmers to create their own types, now we have something that's much more powerful. We call this... They're non-basic types. What type inference, what does that mean? How does the compiler know what the types of your variables are in C? Because you explicitly say what type they are. Yeah, you explicitly tell them exactly what types everything are. Is that cool? Do you like that? Yes. It's nice, six months later when you're trying to figure out. It's inconvenient at the time. Yeah, what about trying to make a change to some code? Have you ever gotten this situation where you use, let's say, I don't know, integer? And at some point you realize, oh man, this should really be a double. So then you have to go through, change that variable type to a double. Then you have to change everywhere that type is used later on if it's passed into other functions, right? You have to change all of that to a double. What are you doing in project four? Magic, you're doing magic in project four. I like that. Yeah, you're doing type checking, but do you have to specify the types of variables? You can, right? You can, but you don't have to. But before, let's say, so we're not actually executing that program, but before you execute that program, does your compiler know all the types of all the variables in that program before you execute it? It can figure it out at compile time. Yeah, right? That's exactly what you're doing is figuring out what are the types of all variables in this program, right? Even the implicitly declared types and implicit variables, you're figuring out based on their usage, you're inferring what those types are, and you're doing it beforehand, right? Whereas a language like Python doesn't do any static checking of types, but it does check at runtime. You can't call a function of an object that doesn't exist, so it will check at runtime. But what you're doing is you're inferring the types based on the usage. So to me, this actually is an incredibly powerful idea that will see how it's done, but that you get the power of static typing without the necessity of always specifying exactly what every type is. Because the compiler can be smart enough to figure it out, and it can be so smart that you can ask it, hey, what's the type of this variable? You can just hover over it in some languages and it'll say, hey, this is this type, yeah. So C-sharp, yes, has the var keyword. There's var and auto, right? I think for auto, I think is the dynamic typing, which basically you get rid of all the types, the static type checking. And var, var definitely does some inference. So depending on its usage right there will infer. The type of inference we're talking about can be much more complex. It can infer types of functions based on usage and types of variables based on what their paths to functions. And we'll actually try to solve the constraints to figure out, hey, what type does this variable have to have in order for it to actually compile? So can it be a list of any type, or does it have to be a list of integers for some reason? Okay. So what do we also need? So is this all we need? So if we do all this, is this it? Are we good? Types solved? We have a type system? Casting types. Yeah. So why do we need to cast types though? Because what are you trying to do when you cast a type? Convert it to a different type to do what? Use. For quick use? Yes. Take up a different amount of memory. Wait a second, yeah? Take up a different amount of memory. Take up different amounts of memory. Kind of. When you cast it, you're telling the compiler to treat it as if it only used a different amount of memory, but it actually still used the larger amount. Yeah. Wouldn't you want to cast something if you wanted to perform a certain operation type that you're casting to? Like if I had an impance and I wanted to cast it through a char, so I could only do something that I could do on a char, I would have to do it at a cast. Right, so it's because, right? So the main idea is how do we know two types are equal? Right, we have to have some way, our type system needs to specify when are types compatible, when can they be used one for the other, right? And what are the rules? So if I have two different structures, right, can they be the same? Do I need to explicitly cast them or can the compiler say, hey, based on the type system, these two types are the same and I can treat them the same? Right? And so that's really the third aspect of the type system. So we need to have, in order to have, create new types, right, we have to have the ability to declare types. So the programming language, right, as we saw is going to include basic types as we've seen. And so this way basic types, right, are included in the language and they're available to any program that's written in that language. But we also need some kind of type constructors, right? We need a way for programmers to construct and create new, complex, interesting types. So what kind of type constructors do we have that you've used? Structs. What is a struct or a type perspective? Continuously allocated memory. Ooh, continuously allocated memory. Let's not think about memory. We're thinking at a higher level about types, right? Without thinking about the kind of hardware or how it's allocated. What was that? They're custom types. They are custom types, but how do you create them? Structure is one. Code them. Yes, but what do you use? How do you, what are the different types of types? What's your name, struct? Yeah, struct is one. Cue. A what? Cue. I can't. A cue. A cue. Ah, a cue. So that would be in like C plus plus, I think they have a cue class in other languages. So how are arrays created? How are strings represented in C? Array of characters. What's the type of an array of characters? Is there, is array a basic type in C? No. It's a character pointer, right? And so by doing that, we've actually created a new type, right? We've said, okay, from the basic type character, we can create a pointer to a character, a character star. And we can actually keep doing that, right? You can have pointers to character pointers and you can have pointers to pointers to pointers to character pointers. And you can have pointers to pointers to pointers to pointers to pointers to pointers to pointers to character pointers, right? And we already just went over all of how to visualize that and understand what's going on there. So you're all experts at pointers. And so the nice thing is we can create with this type constructor, we're calling it pointer to T for any type T, any basic type or any type. So any type constructor. So we can have pointers to structs. Okay. So we talked about structs, right? So what are the defining features of a struct? Type flies, access, fields in the struct. Maybe do this. The name, right? So every field in the struct has to have a name and a type, right? Each of those fields has to have a type. So this is how we're gonna represent. So what we're doing right now is creating kind of like an abstract type system. So we're gonna say, so we have pointers to things. We have a structure, right? So in this, we're gonna say all the A's here are field names and all the T's are types. And so we have to have previously defined types. So what if we wanted to have arrays in our language and we wanted to allow those as a type constructor? What would we use? From a type perspective, what's some of the types that an array has to have? Or could have? Pointer? So it's like we're not gonna use pointer. We're gonna create a new way. A way for programmers to create their own arrays. Just like with structs, right? We have a way for programmers to create their own structures. Which field is an element of the array? The name is declared for that array. Yes, so with arrays, right? We need indexes, right? So what do we need about the type of the arrays? Consistent. Right, they should be consistent, right? So every element in the array should have the same type. What if we wanted to specify the range, right? So this type is an array of zero to 10, or 10. Right, that could actually give us, would this be nice as programmers and as compiler writers? Easy to navigate, I guess. Yeah. Definitely a little bit better, Rex. We have the range, we can specify, we can know beforehand exactly how many elements are gonna be in this array. And so array, this range, we're gonna say it can be either single dimensional, right? For one, or we can do multi-dimensional arrays like this. So we can have an n by m array. So what about for functions? What are the types of functions? And what's important on the types for functions? Return type. Return type? What about parameters? The types of parameters. The types of parameters, what else about parameters? The what? Number. The number, yeah, the number of parameters, right? So we're gonna say we can create new function types by a function that has K parameters and returns something of type T, right? Where all of these T, T1, T2, TK, they're all independent, right? They can all be independent things. Okay, so the type of this is a function and the types of the parameters are T1 to TK and return type is T. Okay, so we need some way to actually use these type instructors. And so very similar to project four, we're gonna use kind of these ways to do type instructors. So we're going to declare types. So we're gonna declare that this new type, cm for centimeter, is an integer. We can define RGBA as an array from zero to four of integers, so it's RGBA. I've seen it before. Yeah, red, green, blue, alpha, right? Which is used to restore like pixel data format. So red, blue, green is the amount of red, blue, red, green or blue in that pixel and then the alpha is the transparency, yeah, of that pixel. And so we can say that well, we can make a PNG, right? Or some kind of image and array of RGBAs, right? So we're building, we're constructing new types based on the other types that we've already declared. So types need names. In distinguisher, because otherwise, how do you tell one from another? Or rather, how does the compiler tell one from another? Or do you say? That is a very good question and we're going to get to that, right? That's from the type compatibility rules. So we'll see later how we define that, right? So let's look at a struct. So have you ever wondered why in C when you write a struct it has to end in a semicolon? No, I just do it. No, you just do it. But it doesn't make any sense because functions don't end in semicolons, right? It's a very similar structure. What's the name of the semicolons? The name? Isn't that like this? Because it's like when you're saying struct in AG and then in structuring it with a Y. Oh, you put the name here, right? Struct foo? Yeah, and then you can put Y on the bottom end. That's not the name though. Y is not the name. What is it? So what you're doing here actually is you're declaring a variable Y and the type of Y has this type is a struct with a field int A and the second field character B. Yes, sir. Exactly. It's going to create a new variable. It'll create a new variable, exactly. But note that in this case this structure has no name. There's no name for this structure. It's what we call an anonymous type. I thought Y was kind of its name. Y is a variable that has the type struct int A character B. Can't you make Y into foo? Where's foo? You can make Y foo. Never mind. You can call Y whatever you want, just to mean the variable that has the value. Exactly. An important point is this is not the type. This is not the structure, right? This is the variable Y that has that type. So you can't create new variables with new types of Y because Y is the variable. Similarly, we could say here that we can have an array of 0 to 4. So we can change... Oh, yeah. So here we're declaring a variable X and the type of X is an array 0 to 4 of int. So an array 0 to 4 int of integers. This type has no name. We didn't declare that this type is a PNG or an RGBA. So now one of the big questions is if I have this X and I have another variable that is a type RGBA, can I assign one type to the other? Can I assign foo to X or X to foo? If they allow it, yes. The big question is how do we do that and how do we make sure that it's actually what we want it to do? So every C, the... and on its type rules, and actually, yeah. Okay, so if you did have a name for that struct, if you wanted to later on refer to it, you would need to specifically say struct and then that name, but for Y, just call Y. Okay, yes. Actually, that's great. What's the same variable Y? It'd be just like having two variables with the same name that would throw an error if they're in the same scope. But if you change the name on each struct, just look at it, okay. Okay, we're going to demystify structs. Does it really matter what these are? No. So right here, this is perfectly legal. You can use this in your program. There's just an anonymous struct. Actually, I don't know if it's actually legal, but we could check. But so usually when we use this, let's say this is struct test. So structure test. So now if we want to say somewhere else in our program, right, if we wanted to use this type, how would I declare that I have a variable that's called X of this type? So we're saying that X is a struct that's test, and we know that test is that type. Okay, so this means, so what this means, this is declaring a variable Y in the global scope that has the type of a struct with an info and a character bar. So can I say Y equals, I don't know, so can I declare a struct Y called Vaz? No, because Y is a variable, right? But I can do things like I can say, I can say Y dot foo is equal to 100. That's perfectly legal. Yeah. So I know for the X when you did, I'll keep memory, but I'm just curious, in the case of the Y struct, does it just inherently have memory like stuff that's static then? So what's the scope of this variable, Y? Global. Global, so then what's the allocation? Global. Global allocation, right? And this variable X is declared where? On the stack, so it's automatically stack allocated. So that's why there's automatically memory for that variable, that structure X. Cool. All right, so that looks like one more example. So maybe you've seen this, usually sometimes you have to name it, we'll call it test two. So what's this doing? So what is the type, what is the type def in C? It lets you use, instead of struct, test two, you can just say test two. Yeah, so here instead of type def, instead of using, every time you use a centimeter, it's the same thing as using an integer, right? This is exactly what this type def line does. So then here, I can actually remove this. So here I'm saying, define test two, right? From here on out, any time I use test two, I want it to be this, excuse me, this structure, this anonymous structure foo bar. So that in here, So you just type less code. So here I'm defining this structure without using the struct. So this is why if you see you've ever been confused as to you're looking at code and like sometimes you have to declare the struct, right, when using that type, other times you don't. You don't have to declare it if you use a type def. So this is why people usually do that because it saves less code. Yeah, the syntax, I think it still works. I mean, we can look at maybe the example code real quick. You don't have to name it. No, you don't have to name it. I think because of the type def, it's fine. Like the syntax is different for a type def than a struct definition, exactly. But I actually don't know 100%. This is 340. Projects, project two, the structs here, project three, and where? Okay, so in project four. Four, all right. There we go. So here's one example, right? So we're declaring enum, right? Expression type in this example as either a primary expression or no operative assignment. And because we use this type def, we don't always have to say enum expression type. We can just say expression type. So it's not like a variable. It's just a name of it. Yes, exactly. The type def means define this new type as that new name. All right, let's quickly try something. So you can still name it? Yes. And then, okay. So the other super tricky thing, if you're trying to do a recursive struct, so let's say I wanted to create this new node type structure, and so I wanted a pointer to itself or some next node, right? So making a linked list with a struct. Is this going to compile? Why not? Yeah, so the problem is the node type is not defined yet. Node type is not defined yet inside this struct, right? It's only defined after this definition. This is why when you do this, if you want to do it like this, you have to do, so you either have two options. You either just don't use that type def and you can say struct node and you'd say int foo foo and then you'd say struct node pointer next. You'd have to do it like this or you'd have to change this. You'd have to define this structure as a node structure and here you'd have to say struct foo. But then later on you can define some node testing and then you can say testing.next is equal to whatever you want. So anyways, hopefully this helps when you're looking to understand what's going on. Cool, alright, thanks for being with me.