 Now you guys just got that secret in-class information on the midterm. Now we'll freak everyone else out, he's listening online, and we will continue. Okay, so we've seen that a type system, right, so a type system, a developer has specific types and a type system defines basic types, right, and then the type system also allows the programmer to create and construct new types using these basic types. So here we have some types that are declared based on we're defining type centimeter as an integer, we're defining an RGBA as an array of 0 to 4 of ints, and we're defining a PNG as an array of RGBAs. And the important thing where we left off what we were talking about is specifically types, types with no names, right? So anonymous types are types that have no name, right? So for y here, y is a variable here, the type of y is a structure that has a field int a and another field character b. What's the name of the type of y? There isn't one, yes, it's anonymous, it has no name, right? The difference would be if we declared some type called foo, and we said that foo is a structure like this, and then we said y is a foo, then we know y's type has a name called foo. So this becomes important when we start talking about how do we decide if two types are compatible or not, right? How do we know if two types, so for instance, when we do assignment, right, what is allowed by the type system and what's disallowed by the type system? So for instance, can I do a equals b? Well, just by looking at this, you have no idea if this works, right? So what if a is an int and b is a float? Do you do that? One is more extensive than the other. What's a pentagon? Is it a trunk at the floor? Doesn't it depend on what's allowed in the system? Yeah, so this is the big thing, right? So in C, is this allowed? You get that loss of precision. I think it's just trunking. I actually don't think it would work. I don't think you can go from a float to an int without a specific cast. I think you can do it and do the specific cast because you're losing information going from b to a, right? You could do it without a C. What was that? You could do int to float and C. Yes. Exactly. So then if we flip them, right? So we say a is a float and b is an int. I don't know if this would work. Can a float hold up to 2 to the 32 or 2 to the 31 integers? Test it. Yes? Somebody create that open. Yeah, I should test this. The important point is that it really doesn't matter because the type system itself has to define if this is allowed and good. And a, if it's allowed and b, what are the exact semantics of doing this, right? In some cases it makes sense, right? Assigning a character to an int makes sense because a character is only 8 bits, right? So it's 2 to the 8th, so we can store that value inside an int. But we actually want to allow a programmer to do that because from the type system, characters and ints are different things, right? I mean, if you think about it logically, right? Why would I want to treat a character, an element as part of a string as an integer? It seems kind of weird. So type compatibility. Type compatibility is the rules about what's allowed and type inference allows us to say what are the types of expressions or some other constructs. So how do we infer types? So this is exactly what you're doing in project 4. For project 4, you're automatically inferring the types of variables in your program based on their usage. But the compiler has to do this as well for other types of expressions, right? Like what's the type of A plus B? It's an assumption. Yeah, we have no idea. We don't know anything about the types. But there must be a type of A plus B, right? Because you can assign that to another variable and you want to know if that type checks. So there needs to be the expression A plus B, right? Has to return some type. And so if A is an int and B is a float, what's this going to return? So A is this going to type check? What do you mean by type check? Is it allowed by the type system? Well, it depends on what rules. In C, yeah. In the project it's not, right? Correct. In the project it's not. What about C? Yeah. In C it is. And what's the type that it returns? Float. What is it? Float. Float? Yeah, so it's automatically going to convert that int to a float and then return a float. But another language is like ML or OCaml. This will actually throw an error. You can't add an int and a float together. You have to explicitly convert from an int to a float. So is this, I don't know, is this good? Do you think that would be a huge pain? Yes. Yes. What? Could it prevent errors, right? Where you mistakenly are adding a float to an int but you really didn't want to do that. You thought that A should have been a float itself, right? So there's this very weird trade off between when things are implicit like this and just work like A plus B, well your, yes it's easier in some sense to write a program but it could cause errors in your programs. What about A times B? If A is an int and B is a float, what does it return? What does it return? Probably a float again. What if A is a string and B is an int? You said in Python you can do that. I did say in Python you can do that. Yeah, that's the next thing. Right? So it depends on the language, right? The language has to define what does this mean? You can do that in Python. Yeah, it's an error in most languages and it returns a string in Python which still bugs me. It's actually really useful but it's super annoying because it doesn't make any sense conceptually. Like why is string multiplied by an integer means repeat that string that many times like that, yeah. You're asking why would you want to do that? Oh, I do it when you're doing like security testing and stuff and you want to see how big like a buffer is. You want to pass input to a program and you give it consecutively larger and larger inputs. And so with this you can use just like an A times whatever number and you can just keep increasing that number to get more and more input. So it actually is really handy in those cases but these are one of those really weird corner cases where it doesn't make the code any more readable, right? Especially if you have variables, right? If it's A times 10. Okay, then maybe I know A is a string but... And JavaScript's even worse. You can do this in JavaScript. I believe it will try to figure out, it'll try to look at A, see if it can convert A to an integer and then do the multiplication. So it'll actually try to see if you pass the value as like if the string of A is 10, it'll interpret that as the integer 10 and the new 10 times B. And then if not, I don't know if it returns zero or not number is really crazy, so. And we've seen this is kind of a... So this is just about type inference saying that the expressions, right, have to have some sort of type, right? That way you can make sense of them. This is why in project four when we say something plus something, so from plus it's defined for everything with integers with ints, right? Something, an int plus an int returns an int, right? That's the type of that expression. So that's part of type inference. Okay. So the main question we want to answer with type compatibility is, are these two types equivalent? Right, so let's look at some examples to try to understand, well, this seems like a trivial problem, right? It's really easy to see if two things are equal, right? So let's say we have a centimeter, a type centimeter, so we're defining, we're constructing a new type called centimeter that's defined as an integer, and we're defining a new type inch that's defined as an integer. And we have variable X which type is centimeter and variable Y whose type is inch. So we can say, can we say X equals Y? We guess they're both integers. Types are not. So I want arguments for one side of the other. So should you be able to do this and if so, why? Or should you not be able to do it? I'm going to say no because at the time of type checking it's going to look at X and say this is a centimeter, look at Y and say this is an inch, they're not the same, can't assign. Okay. But I mean, like, okay, when you, characters work like that though, because a character is the underlying type of a character is an inch, right? It's a byte, actually. It's only because it's a smaller inch. So it's eight bits, or is it an integer if you do 32 bits. But are there primitive types that have, like, underlying types? Float and inch are both 32 bits. Okay. So I mean, in this case they are the same underlying types. So they should be able to do this. So you should be able to do this. I mean, unless it's like mission critical, in which case not. Unless it's mission critical and you don't want it to happen? Well, yeah. So the compiler should know that this is mission critical code. Well, in most languages, those two are not types. So like, I guess the person defining them should have a way to make them unequal. Yeah. I think you should be able to do this because centimeters and inches are not the same thing. So if you set centimeter equal to inch, it's just not going to be right. For example, if we have one inch and set x equal to it, it's still not actually one inch. It's one centimeter. Yeah. So what do you want to happen as a programmer? Yeah. Not. Wait, as a responsible programmer? What other kind of programmer are you? Are you an irresponsible programmer? You could make it do the conversion for you. That's true. You could make it do the conversion for you. Interesting. Well, that just depends on how the assignment operator works under the hood. Question about the potential of a test. Like, when you ask something, is this valid, like x equals y? And like, do you want us to answer that question yes or no as in like, in the C languages? Is this a valid thing? Yes. I mean, I would give you a question like this. This is a discussion question, not like a test question. We'll see the different types of type equivalents. And then I'll ask, hey, would this be equivalent in name equivalents and structural equivalents and the different types of equivalents? Yeah. Anybody else have any other thoughts on whether you would want this or not want this? Well, this kind of goes back to the previous question. We asked earlier, you know, into flow, flow to N. Only one of those is actual support. And that's more a language specific thing. Right. So in this case, I mean, in that case, an N and a flow are both numbers. So they're easily convertible. I mean, an inch and a centimeter are not, they're both measurements, but they're both very different numbers. They have different conversions. Are they easily convertible then? They are easily convertible, but that has to be supportive of them. There you go. We don't know if it's supportive. So there's a couple of issues at play here, right? One is the developer is creating these new types. Right? So, yeah, I agree with, actually, you guys have touched on a lot of issues, right? So I agree with, from a programmer's perspective, this should not, we do not want this to just happen. Right? Because we don't want to be able to just, one inch is not the same thing as one centimeter. Even though it's the underlying system, it's representing, you know, to the underlying system it's representing it as integers. Right? I mean, to the underlying system, everything's ones and zeros, right? So then we don't need a type system. So this helps us not shoot ourselves in the foot, because here we can actually define a new type as centimeter, right? And we know that anytime we assign it, we're only assigning centimeters to centimeters, right? As opposed to being able to accidentally assign inches or feet or whatever other kind of value we have. Actually, the comments on automatic conversion is actually very good. There's languages like Scala do, you can define new types, and then you can define, it will actually, I think if it sees something like this, it'll try to look and see if there's a function that will take in an inch and return centimeters. And so it'll try to automatically convert for you between those two values. I think maybe you have to specify exactly what those functions are, but yeah, it's kind of nice because you can say, you can use this, and that way anytime you use a centimeter or an inch, you don't have to worry about the conversion between the two. I also feel like that could backfire rather magnificently if you weren't thinking too hard about it. Lots of things get backfired. If it's trying to use the wrong function or you've previously defined a function incorrectly, I mean you can dig in through. Oh yeah, it's kind of the same argument against C++ and operator overloading, right? When you look at a program, it's really hard to know what functions are going to get called because this equal sign may actually be some really complicated function that gets called and all these other things. Actually that also brought up a good point, right? So centimeter, can you actually convert from centimeters to inches without losing precision? Not as an integer. Not as an integer, right, which is how they're defined. So that's another interesting point. So, the main thing is, this is trying to get you to think about what does the language do and how is that good for me, the programmer, right? Is this actually the behavior that I want? So we're going to look at, I believe three, this is why you should never number things. We're going to look at some different types of type equivalents. So the first one is the very kind of easiest example and it's name equivalents. So just using your powers of inductive reasoning, what would you think it's going to check for to say that two types are equivalent? The name of the type. The name of the type is equivalent. Yes. So they must have the exact same name to be equivalent. So, in this case, if we have a centimeter and an inch and we say, can x equal y, would this be allowed with name equivalents? No. No, because it's checking the exact names of x and y and say, okay, the type of y is inch. The type of y is centimeter. Those are not the same type. Therefore, this is an error. We can't do this. Do you want us to print out an error? No, I want you to know how to use this name equivalence to be able to look at type definitions and say whether two types are equivalent or not equivalent. So where is this? So this seems very straightforward, right? Okay. Where is it tricky? So there's one thing that we talked about in this sentence. So let's think about it this way. Do all types have names? Unnamed types. Not unnamed types, close. Anonymous types. Yeah, that's the specific word for that. So we want to look at another example. So let's say we have a, which is an array 0 to 4 event, b, an array of 0 to 4 event. So we want to say is, okay, so yes, we're declaring a variable a that's an array 0 to 4 event. We're declaring an array b of array 0 to 4 event. So is this allowed a equals b? Well, we have to make an argument for one way or the other. Based on what we just learned about name equivalence. No. No, I know. I think it is. We'll think about this in terms of c. Maybe you're just pointing this. You're just assigning the pointer. So technically. I don't think about it in c. I want to think about it a bit more abstractly using what we just saw. Well, neither of them have names that technically do. I guess that is the philosophical point. Okay. Types must have the exact same name to be equivalent. This is what type name equivalence means. Right? The types must have the exact same name. So what are the types of a and b? Array. Array. Array. Array. Array. Array. Array. Array. Size of the array. Is that part of the name of the type? Yes, it's part of the type. Okay. Yes. So the type of array specifically has the size or the range we call it. And then the type of each of the elements of the array. So they're both in. It's close. Yeah. So these are both anonymous types. Right? So the type of a is anonymous. The type of b is anonymous. What does it mean for something to be anonymous? Has no name. So if it has no name, can it have the exact name to something else? Well, technically, they're not a name. And not a name is equal to a not another name. So I guess. It really just depends on how you define it. It does, but I'm trying to guess the thing. You're fishing for a specific answer. If somebody was anonymously wrote, let's say, feedback to me or something on your reviews, if I get two pieces of anonymous feedback, I wouldn't say, aha, these are the same person. How do you know? I don't, but I can't assume that they are. This says they have to be exactly the same name. So if I have two types with no name, that could be the same, but they could not be the same. So in the case of anonymous typing, we have to assume that they're not the same unless specifically defined as the same person. Yes, specifically for name equivalents. So name equivalents, they have to have exactly the same name. They don't have names, so therefore you can't do equivalents on things that have no names. So this is not allowed under name equivalents, right? But is this what you want from your type system? Sometimes. That's not really enough. Was that enough? It's not enough. It's not enough? And not enough in what sense? Capability. So we would, I would like the ability to say that these two arrays are the same type. So it needs to be able to figure out that, oh no wait, even though they don't have names, they're, when you look at it, they're the same. By any means, some sort of signature. Right. So it's, the thing is, yes, so they're, they have no names, but they have, well okay, well it's actually, we're going to look at some other things. We're going to get back to this about, sometimes the structure of them are the same, right? Okay. Let's, okay, so on that example, right, we had A is an array, I'm just going to say array of int. So I have a variable A as an array of int. So what about, and here I had B is an array of ints. Does the size not matter in this case? Yeah, for space reasons I'm not drawing the size. Okay. So what if I declare, so we saw in project four, right, in a lot of programming languages, you can define a variable kind of on the same line, right? So you can say that, well I have variables, let's say A and B, and the types of A and B are both arrays of ints. Should A and B be equal here? Why? Because we define them on the same line, they're in the same state. Okay, so we define them on the same line so they should be the same type, right? I mean we're saying, like if we say, I don't know, X and Y are both ints, right? We should say X is equal to Y, right? So can we do this under name equivalence? With the integers yes, with the arrays not smart. X and Y yes, because the names are identical, right? The name of the type is int, the ints are identical, yeah. Can you just give the type array of int a name? Yes, so that's one way we can do it, definitely. So we can say, like in our language, we can say foo, the type foo is an array of ints. And then I can say, well A is a foo, and B is a foo, right? So then can I say A is equal to B under name equivalence? Yes, because they have the same name, exactly. But what if we go back to this case? So by name equivalence, right, what's the name of the type of A here? It doesn't have one. It doesn't have one, and the name of the type of B. Also anonymous, doesn't have one, right? Under name equivalence could be different. So under name equivalence, we cannot do this, right? So it's an error. But does this make sense? Okay, it makes sense for a name equivalence, which is good. But is it what we want? No. No, right? Because we're defining these two. So what's the big difference between these two? They're independent statements. Right, so here up top, I'm declaring a variable A, and then maybe 100,000 lines later, right? I'm declaring some variable B with the type of array of int, and it just happens to be that they have the same type. But here, I'm declaring on the exact same line, I want two variables, and I specifically want them to have this type array of int. That line says that they're both the same signature. Same type, the same anonymous type, right? So there's still no name here, but because these are declared on that same line, as a programmer, I'm basically telling the compiler, seriously, these have the same type, right? How do they not have the same type? They have the same line, right? So this gets to the next type of equivalence that we're going to talk about. So we just saw up, right? So under name equivalence, this is not allowed because this has no name. But it doesn't make any sense, because we're defining variables, multiple variables, and we're saying these have exactly this type. Okay, and we saw this. We can say we can do this, right? Because we've both given a name to this array, and so now we know, great, these are definitely the same type. Okay, so the next type of equivalence is internal name equivalence. And this is kind of a little bit peeling back the hood of the compiler just a little bit. The basic idea is if the program interpreter, so the interpreter or compiler, would give the same internal name to two different variables, they share the same type. And this specifically covers this case, right? So internally, just like you know you're doing project four, internally you have to have some way of representing the types. And so when you see a new anonymous type, you're creating some new type for that new anonymous type. So the compiler does exactly the same thing. When it sees this line, it sees, okay, new anonymous type array, and okay, A is also this type and B is also this type. Then when it sees this declaration C, it's going to create a new internal type for this array zero to four of it. Because it's an anonymous type, it's never seen it before, so it has to create some new type for it. So with internal name equivalence, now can I say A is equal to B? Yep, yep. Why? Both array side zero to four. Yes, internally they have the same internal name and we know that because they're declared on the exact same line. And it actually follows more closely of what our intent as programmers are. We're declaring that these are exactly the same on this line, so we should be able to do this. But can we do A is equal to C? No. No, because the compiler's going to give this a completely different name because it's a brand new anonymous type that's never seen before. Questions on this? Equivalence, slightly more expressive than our low, I guess, less restrictive than name equivalence, right? So it allows you to do this. Any questions? Here. 15 minutes, nice. But I guess we still have to ask the question, does this really make sense that A and C I can't assign them one to the other? Not really. Yes, but it's not what we wanted to do. They're the same. Yeah, I mean it makes sense in some ways, right? It goes back to the same argument with inches and centimeters, right? We're using these arrays for completely different purposes, right? And so I want them to never be able to assign to the other. But it also makes sense that, well, really they're the same things. They're structurally exactly the same, right? You could copy, you know, the size of each array, so you could copy every element from C to A, and then you successfully copy one to the other. So this is where we get to structural equivalence. So the idea is the compiler is going to try to determine if these types are structurally equivalent, so if they have the same structure. So we build this up, we have a series of rules basically. So the first thing is, right, built-in types are the same built-in types are structurally equivalent, right? Makes sense. That's kind of, if you think about this, this is a recursive definition, so this is our base case, right? So at the end of the day, we're going to have built-in types. Then any pointer to structurally equivalent types are structurally equivalent, right? So in this case, in structural equivalence, right, I have centimeters, I have inches, these are both the same built-in type, right? So this is a loud-in structural equivalence, which as we'll see gives us some nice properties, but it kind of also hurts us in this way. So for pointers, right? So I have, yeah. Shouldn't the equivalence kind of be hierarchical, I guess? So the very first thing it looks for is your name equivalence, which in this case, it would pass, and then that's where it stops. But if it can't name equivalence, then it goes to the internal type of equivalence, and then it goes to the structural equivalence. You can think of it like that, but it's not what's actually happening. I mean, so for two things to have the same name, they're going to be structural equivalent. And for two things to have an internal name, they're going to be structurally equivalent. So you can kind of think about it both ways, right? So the structural equivalence rules kind of imply those other ones, right? Or, sorry, the name equivalence implies structural equivalence. Again, that would be a good check, I guess, on the test or something. Because they both have integer. But these are not name equivalent, right? So that actually doesn't show here. But if you have two integers, right? Two integers are name equivalent, and because they're name equivalent, they must have the same structure, right? And if two types are internal name equivalent, they also must have the same structure. So let's look at pointers. So we have an int star a and a float star b. Are these structurally equivalent? So we first have to peel this back, right? So we first check, and we say, okay, a and b are both pointers, right? So that's structurally equivalent. But, as we saw in this rule, pointers are structurally equivalent only if they point two the same, point two structurally equivalent types. So we see they're pointers. Yes, okay. That's structurally equivalent. And then we see, okay, but this is an int. Int structurally equivalent to a float? No. No, because only built-in types are structurally equivalent. So this would be not structurally equivalent because the int and float are not structurally equivalent. Now a big problem becomes, so basically what we're doing here, all these rules are going through all the type constructors, right? And saying, okay, here's how you create new types. Here's how you construct new types, and here's how you can tell types are structurally equivalent. So now we need to do, so how do we determine if two structs are structurally equivalent? What do you think? What makes sense? Check a bunch of things. Yeah. To look at the elements of the struct and see if they're the same, and if they are, then you treat it just like you did with the pointer. Yeah, so elements of structs are the same, right? So you could say, well, what about the elements of the struct? They need to be of the same type. Yeah, so you need just the same type where you've got a bunch of ints on one and one ints on the other. They're the same type. Same type, same quantity, same order. They need to be the same struct. Wow. Well, I guess they had to be the same order if a struct is made of multiple primitive types. But even then, I don't know, I don't think they would be the same order necessarily. We assign structs type names, and that just handles this for us because if they have the same type name, everything inside should be the same. Yes, so if they have the same name, then they're name equivalent, right? Which means they must have the same structure. But like in the previous cases we saw, we want to see if these two types are structurally the same. So we have to assign one to that. Exactly, yeah, so we don't have that. They're two anonymous types, right? We have no idea. In the internal structure, every element has to be name equivalent to the other structure. So if it doesn't necessarily have to be the same order, but if it's two n's in type A and A and B in both structures, regardless of what their order is, then they're the same. Yes, let's think about this. So we have two structures, right? So we have structure two, which has fields x1, which have type w1, and we have structure two, which has fields y1 through yk, y1 through qk, right? So the first thing that makes sense, right, is that the number of elements of records in the structure, fields in the structure have to be the same, right? So that's why we have the k here. So k means they have the exact same number of fields. So actually, well, a couple different ways to think about this. So we say that, okay, two structures are structurally equivalent, and now it really depends, right? So there's actually two ways to think about this, right? What is a structure? Is a structure, are the fields and the field names of the structure more important than the order? What do you mean by that? Fields are defined in. Let's think about this. We'll give it a name. I have an int called A, and I have a, well, something that's definitely not an int. Charm. Yeah, I can find it. There we go. So I have struct foo, and I have a struct bar. So, are these structurally equivalent? Arguments for both? Yeah. So when you call upon elements of a struct, it doesn't really matter where it is. You just call struct. whatever you're looking for. And in array, in array it matters. So I think you think of a struct kind of like where it has an index, and it's in a specified order. That does matter. But is the name just an alias for the index? I don't know. Yeah. These two structs could potentially be different sizes based on the length of the string. Ah, let's say that the string is like a current pointer, so it's only a fixed. But yeah, that is a good point, right? If that was a dynamically sized thing. Yeah. I'm not even on the language, I would say, but to be honest with you, in C, I don't think these two would be equivalent because I would say a thrown error that this struct, if you would like put them as equal, you would say error because it's expecting struct with int string, and you gave it a struct string int. So that would be an error in C. And like for example, in C, struct would be the same thing. But there are languages in which if the int a and int a in both situations is the same and then the string are the same length as he said because the length could be different. Okay. If you see other equivalent and then you try to use a byte offset instead of like an arrow or the dot to access the new current other problems, you'd have to like disallow that. Yeah, okay, so this is actually where we get what is a struct. Abstractly, a struct just groups types together. And it gives us a way to reference each of those grouped types. So actually abstractly I would say that yeah, you'd actually kind of want these maybe to be the same type. The problem is once you can start thinking concretely about how this is actually implemented. So in C, a struct is just a contiguous chunk of memory. So if we said that the string was actually a char star, this would be 4 bytes for character pointer and then 4 bytes for an int. Right? This is contiguous memory and the other way, right, we have an int followed by a character pointer. So in C, the way it's actually implemented, the names mean nothing. It's the order that means the most. Because this character pointer the int is essentially it's kind of like thinking about it as an array. The int is the second element of this structure. But the int here is the first element of this structure. So I'm trying to assign these to each other or copy one to the other into the memory is going to completely mess things up. It's like a key. In what sense? Which is the key. They're both different keys. They're both, so the problem is the order here, right? So this is the way we're going to think about structs, is this kind of C style where the order of the elements in the structure matters the name. In fact, the name doesn't matter at all. So in our structural equivalents these would not be structurally equivalent because the order is different. But if we had let me get rid of this guy the order is the key. The order is the key, yes, and only the order. So if I had some struct bar that was an int d and a string e would these be structurally equivalent? Yes. So they have the same number of elements and each element the types are structurally equivalent. We have an int, we have an int, we have a string, we have a string, these are structurally equivalent. So though they are structurally equivalent, what if you don't want them to actually be able to become equivalent? You can't. You have to have some way in your type system to construct a new type that is different from an int. Kind of like a new basic type in some sense, but in structural equivalents just not its own you could. More the ideas looking at this idea of how do we define if two types in this sense, but also data structures kind of, if they have the same so this is exactly what this says. Structure 1 and structure 2, they are structurally equivalent if and only if w1, which is the type of the first field, is structurally equivalent to q1 and the same thing of w2 is structurally equivalent to q2 and so on and so forth all the way to wk and wk and qk. So just matching the types notice we don't say anything about the names of each structure. We don't care at all about the names here. So, we've seen here we have a structure A which is an int followed by a float structure B which is an int followed by a float so if we declare a variable A called foo and a variable bar with type B we say can we do foo is equal to bar? Yes, so specifically note, even though the names are completely backwards and weird the types are the important thing here and the same thing as we just looked like we have an int and a float and a float and an int because the order is the important thing here these are not going to be structurally equivalent. There are compilers that will optimize the order of structs so that they don't waste memory Usually no. Well the size would still be similar to what we were Yes, but oftentimes you need to be able to cast a random memory into a structure to be able to interpret that so that's like a lot of the networking protocols when you get a packet you cast it to that struct because you know the first two bytes should be this field and the next three bytes are this field so you represent it as a struct but really it's just a sequence of bytes that came off the wire and so that's how you actually interpret it so oftentimes theoretically they could but I don't think it's C and it could be a keyword you can specify that says like never change structure is layout yeah okay and so arrays are done very similarly so if we have two arrays T1 which is an array of range 1 and T2 is an array of range 2 we'd say they're structurally equivalent if the ranges are the same the ranges have the same number of dimensions and the same number of elements which makes sense and T1 and T2 whatever are inside the arrays are structurally equivalent okay so the sizes are the same and what's inside them the order doesn't really matter right because everything inside an array is the same type so we're saying that the type of everything inside both arrays must be the same so the last thing functional equivalents so we say that two functions are functionally equivalent if so we have two functions right what would you guess what are some of the conditions here yeah if the types and the orders for the parameter list are the same and if they return the same thing yeah right it follows very similarly right so A it has to have the same number of parameters right so we have to have K so the same number of parameters and all the types of the parameters are structurally equivalent right in the order and the return types are structurally equivalent cool it's an extension of an array it's an extension of an array kind of actually you can think about an array that is a function that maps an int to the type of the array but okay so when we come back, oh god it will be next week we'll do how to determine structurally equivalent because we'll see it's actually not as straightforward as we just saw because we can have recursive types or types that refer to other types that refer to the factor themselves so how do we determine structurally equivalent tonight