 Okay so we are ready to start and today we'll reinvent object oriented programming from first principles. At least I'll try to guide you through it. Before that I want to announce one review session before the exam. You did have the recitation section yesterday and there are two more topics that we should cover and when it will be tomorrow 11 in the walls in Soda Hall. I realized that I may not work for everybody but that's the time that's available. Another thing project proposals are due Sunday. I hope you have been thinking about what to propose and I know I owe you a few more slides and those will be posted today. So going to the topic of the lecture where are we today? So we looked at a lot of constructs so far and a lot of them were about control abstraction. Can somebody try to characterize what control abstraction is? What sort of constructs fall under control abstraction? So what is, this is correct, coroutine loops if else, backtracking maybe. What is common to all of them? Is there some one property that unifies all of them? They change the flow of the program. If it was a program where PC program counter is visible they tell you how the program counter jumps from expression or a statement to another one. So these are indeed those. We build lazy iterators. You could think of it as another construct on top of lower level construct on top of coroutines. We did backtracking for regexes again on top of coroutines. We searched for a proof tree. The search itself sort of jumps from place to place in the space of proof trees and that search was hidden in the prologue interpreter again implemented on top of coroutines. So if there is a control abstraction there must be a data abstraction too, right? You would think. So what would be some examples of data abstractions? They should be 61B stuff, maybe 61A. Dictionary is hash table. So just data types that hide a lot of stuff inside. They come with an interface. They hide the implementation. They allow you to think of it differently. Perhaps they implemented as link lists but you don't need to think of it as link lists. You can think of them as truly infinite maps from keys to values and you can forget how they are implemented. They could be parallel. They could be sequential. They could be implemented on a quantum computer. You don't care. What other data abstraction can you think of? Try to make a parallel to the control abstractions. You see how much we have been able to hide under prologue, under backtracking. What sort of stuff do we often hide under data? Encapsulation and inheritance. So essentially the whole business of object orientation is a programming model of hiding implementations under the interface of methods and maybe fields. And this is indeed the data abstraction we'll talk about today. But there are others. Can you suggest more? Yeah. Maybe you could say that. I'm not sure I would. Yeah, sure. Why not? Floating point number, for example, also has an implementation that you don't need to know although unfortunately often you do need to know. Algebraic data types sort of similar but not quite the same as objects. They come with some operations and the operations are what they decompose the algebraic data types. The algebraic data types are like trees, essentially like the terms we've seen in prologues. You construct them. When you build them, you deconstruct them when you want to use them. Abstracting where the source of the data come from. Oh, I see. So maybe you have an object attached to a server and you read a method thinking it's all stored locally but it's not. So again, the implementation is hidden. All right? So perhaps the most famous data abstraction that really drives most of the Internet is what? I guess there might be more answers than one to this, which is even better. A database, right? A relational database or not even relational but thing of relational database, it looks like a bunch of tables defined according to a schema. The implementations in the database could be arbitrarily complex for performance reasons. Yet it looks on the surface like a bunch of really simple relations accessible through SQL, which again is relatively simple. More before we go on to objects? All right. So let's look at objects. So from 61B, you know something about objects. What are they? Why would you care about building objects? Presumably they raise the level of abstraction in what way? Okay. That's not what I have here but it's going to put together essentially the behavior of the object, which would be the methods for accessing the internal state and they hide the internal state, the data. So that together is defined as the behavior, the state and the methods. What I have here is hiding implementation under a encapsulation perhaps that's close. Well, good enough. So how about inheritance? Why objects often come with inheritance? You don't have to have inheritance with objects. You could have just objects that, you know, package methods and hide the data, the state. There is no inheritance but if you do, why would you do it? You can reduce code duplication or facilitate code reuse, right, rather than re-implementing everything. You just take what's there in a class and you say, hey, my class is like the one here except I need to override something. And if you could change the behavior by overriding a few methods, your lucky inheritance does give you reuse. Not always works that way but often it does. So through the specialization, you reuse duplication or enable reuse whichever way you want to look at it. So the design rationale is we want objects. We all have some idea of what they are and it's good that we haven't really pinpointed what exactly is an object in terms of methods data because each object model is different and whatever we end up defining today may differ from what you are used to from, say, Java. But we now come to the key question in 164. How big needs to be the base language on which we build objects? We would like the language to be simple through, so that through metaprogramming, syntactic, sugar, you can define objects that are as powerful as in Java without having to build a huge Java or C++ compiler. So how little is enough? What constructs do we need? We just need lambdas, right? Do we even need lambdas? I guess we do need some way of, okay, lambdas, we need lambdas. That's true. Why do we, why are lambdas enough? Okay, so through closures, they maintain state because you create a lambda. It carries with itself in this double bubble. You are still the generation of the double bubble, I suppose, right, rather than the new 61A carries itself the pointer to the environment where you can keep the state and that's essentially the fields of the object. How about methods? Right, you would like to have an object with multiple methods maybe, right? So how do you fake that? So we know we can capture state and carry it as part of the closure. So having a sort of a pointer to a closure, a closure itself carries the state. It's mutable, that's great, multiple methods. So how do we do that? So the answer is we can have a dictionary or something of that sort, but now we have more than closures. Of course, the dictionary can be implemented with closures. So ultimately everything is just a closure. Right, so we are now going to the various design points. That would work. So let's box through them. So we have closures, they support state and they bind together states in the environment and code. Now, how do we build something out of them, right? So the single method approach, where have we seen actually already objects that carry state with themselves and are nothing more just closures? Iterators would be exactly such objects, right? They have arbitrary state that carry from lubiteration to lubiteration. Each time we call them again, they give you the next element or whatever is the moral equivalent of that and they remember everything in that state. What is that one method that they support? That method is not named, but when you call that iterator because it's a closure, it's equivalent to calling something like next, give me a next. At least that's the protocol when the iterator is used in a loop. So exactly these are the iterators. And that essentially there is nothing more to be really said about that they are essentially already objects. Now let's make it more interesting and let's support multiple methods and we could do it that way. So can you look at this protocol? I like to defining these sort of object-oriented small languages will go through by starting from the client side, from the point of view of the users of those objects. So this is above the abstraction. So this is how they could look like. Can you imagine how you would implement these objects? Okay, you can. And it looks exactly like this. There is nothing special. Here you have the constructor which is a function. The object that you return is a closure, a function that now receives the action and it acts accordingly, right? Here is one method, another method, and look it even has error handling. So it looks good to me. Should we just stop here or are there problems with this approach? What is it that you don't like? Okay, so that's a problem, right? Get clearly doesn't need the second argument and depending on the language. Okay, so here we call the set with another argument. Here we call get with just one and because I copied it directly from the Lua tutorial, this will work because Lua will allow you to have variable number of arguments. In 164, since we didn't implement it, we actually would have to provide the second argument, otherwise this code would be problematic. Okay? But in Lua where we have this extra level of flexibility which would be easy for us to add, we could write it like that and perhaps it's not so bad. Okay, so we could have a model where we say d set and now you have a lambda and now you could have whatever arguments you need in this case one or you would do the get. The return value is a lambda with zero arguments and you would call it like that. Okay, that's a great idea. So you would essentially circumvent the limitation that we have which is we are sticking to the number of arguments. That may not be a limitation. It may be a good idea. It's a safety check. So I'm happy with that. Should we just sort of call it the day and go home or are there problems with that? Again, getting ahead of yourself. We don't have dictionaries yet. I didn't give you dictionaries yet. So you could and indeed we'll get nicer things with dictionaries. But I'd like to see challenges here, right? You design this. The little tutorial looks good. This is sort of the example you would write for your project proposal. Everything looks good. Now try to predict, extrapolate from this. What nasty code programmers may write on top of your language? Do you want them to? Do they want to write it? Will they shoot themselves in the foot? Is this too flexible? Not flexible enough? So let's see what sort of object-durated programs would people write. And will you regret those decisions 10 years down the road? Which is the story of most programming languages that people say. If only we knew that this is how those programs would look like. If only we knew that people would not correctly check the out-of-bounds accesses in C, right, which is sort of half of the internet security flaws. So let's try to look 10 years ahead and see what people will conjure up in this language. It's prone to typos, all right? So what sort of typo could you imagine? So the method name, if you have a typo, you will only discover it at runtime, right? That's true. But you could say Python, JavaScript has exactly the same problem, right? I don't think that if you just write a name of a method that doesn't exist, you need to discover it by testing. This is not necessarily bad. You should test. So if you have a battery of tests that is perhaps a bug that you would catch. I agree with you that it's a bad thing, but there is a proof of languages that don't do this sort of check and they run the internet like JavaScript. So, all right, other problems you can see. This is a sort of a problem. Oh, I see. So the answer is that this abstraction is sort of leaky because it exposes a lot about its implementation. So what do we expose here? Let's look at the implementation. Well, you know the object is a function. You know you need to give it a string, but aside from that, sort of we are hiding stuff, right? So are we leaking anything dangerous? I mean, you know that the string defines the name. Clearly you do, right? If you know the language, you can tell that that's the case, but could you somehow abuse it? I think that's really the question. You know, because if you say that I can tell that the object is a closure versus a string versus a dictionary, that's not such a bad thing to know as long as you cannot get that if you cannot as long as you cannot get at the internal implementation. So here you know it's a function. You know you need to pass it a string, but perhaps that's not so bad because you cannot really see how these methods themselves are implemented. Right. So if we do this, this sub-expression does return the function, but I don't think there is a harm to that. That's a function that presumably is a closure has access to the internal state. We cannot really do anything with it. It's not like you can disassemble its body. So that's perhaps okay. So is this really so good? That's fine. We could go home. So maybe it is just stylistically ugly. Maybe it is the fact that it's harder to build tools which check whether your names of methods are misspelled, but there must be something dangerous that people would do. So the set method, yes, it takes the value here and assigns it in here. This value becomes part of the closure, right? This we hopefully understand. Yes, it could, but I think the same could happen in Java, right? Unless you do precautions and explicitly put. So that again is not such a dangerous thing. Okay. So that might be a problem that building inheritance might be difficult. And in not saying it's not possible, but it might be a little bit clunkier and more error prone. All right. So that I think is a problem. All right. So you may want to have some methods private and that's we are not doing that here. Okay. So I'm not sure we can change the name of a function because I see. So the object is a function and now you somehow swap that function all of a sudden it's surprising. You could do it, but I'd say it's probably no worse than in JavaScript taking one object, swapping it for another and then getting a surprising behavior. So that's probably no more dangerous. I see it might be possible. I don't see immediately how. Okay. So I think I like these two answers partly because I have answers to them in the rest of the lecture. So let's go with that inheritance and privacy. Okay. So now I'll give you tables. All right. So let's see what tables are. You can create a table with a literal literal that means an empty table or a table that already has some key value pairs in it. Nothing magical here. And you have two operations. You can assign a value to a key in a table. So you add a key value pair or if that key value pair exists, you override the value and you can read it out. That's it, right? Now, how do we build objects from it? So let me show you one proposal. You create an object. It contains exactly one field, balance. So this literal creates an object. A new one each time this line is executed, of course, right? The literal always creates a fresh object. Has one field we call the object account for obvious reasons. Now we set up a function in it. So now the object is going to have a second field called we draw, which will be a closure valued field. And here is the body of the function. It reads that balance field and subtracts the value and stores it back. So far so good. Okay. Now this obtains the function and we draw $100. So we like it except for the visual appeal, right? So should we suggest some syntactic sugar to clean this up? The dot notation, all right? So we'll do the dot notation. And how do we design the dot notation? So we want to take something like P dot F and turn it into something like that. Okay? So let's write a grammar. What would the grammar look like? Now we have already in our grammar this for writing into a table, we have this expression for reading from a table. What would be the syntactic generalization of that? What would be the grammar rule for P dot F? Well, you're saying E dot ID, why not E dot E? This one makes sense. Oops, I'm sorry. It does make sense. You evaluate this. It could be arbitrary expression, including another P dot F. Here is the dot and here is the name of the field, which would be turned here into this string. All right? Looks fine. But why not make it more general? Why couldn't that thing after the dot be an expression itself? So, all right? So we could in principle have after the dot an expression that could be a function call evaluated, it better returns a string which we then use as the key for that object. All right? Not everybody likes it, so fine. All right? No, this is an excellent point. So what he's saying is that if you write something like P dot F, value evaluate P, it has a value, presumably a pointer value of a dictionary, a pointer to a dictionary, whichever you think about it. And the point here is that we are not evaluating F. We are not thinking of it as an expression that we would evaluate its value should be a string and then we use that as a key. We are just using that as the name as a symbol. Well, but if we opted for this, we would apparently agree that we are going to evaluate it. And that could be fine except our programs in the normal case would look funny, right? Because we would have to write, how would we have to write it if we want to say just P dot F? We would have to write it this way. Exactly. Fine. So, but this is the reasoning that we want to do when comparing this versus that because, you know, the first side looks like why not have E there? It determines the field that you are reading. There might be other problems with allowing anything behind the dot. All right? So there is the dramatic ambiguity, right? If you do something like let's just do, I don't know, P dot, you would need to determine whether this is parenthesized this way or whether it is parenthesized that way, right? And so all these questions, of course, of ambiguity would have to be resolved somehow, but, you know, we would pick something and probably be confusing, but we could always somehow set the rules. Another one is that, yeah, what problems do you see if we allow the name of the field to be computed? Right. So in some languages, typically you have restriction, keys cannot be anything. In JavaScript, they need to be strings. Python doesn't allow, I think, dictionaries for keys. It needs to be hashable, data type. But that would be fine. You know, even when you are using dictionaries without the extra sugar, you cannot put anything for keys. So I wouldn't say that we are adding a restriction or freedom that doesn't exist in other parts of the program. What I think would be really hard is that it would be harder again to check the program because you just cannot look at the dot and the field name and be sure what you are calling because all these are computed. Whereas when you say whatever is after the dot needs to be a symbol, then look at the program, you know, which fields are being accessed. And there is redundancy because we already have the square brackets for that feature. Exactly. Perfect. So this is the sort of reasoning that you want to do when designing your constructs for the final project. So that was a little exercise for that. So here is the same thing rewritten. Now, however, I am asking you to see whether this model we have, the object-oriented model, is good. I'm claiming that I can insert here a statement such that the last line is going to crash. Excuse me? Is it A equals null? Well, you could say A equals null, but this is sort of something a little bit less obvious, something that could happen in a more sneaky way. So A equals null, of course, would be such an error, but you're allowed to do anything. That's legal in the semantics. Sorry, we're both speaking at once. Can we reassign account with draw? We could do that, yes. So we could have an assignment here account dot with draw. And what do we say here? Now, we could do that. And now, this is null. And there is something else that seems to be more sneaky to me. Account seems to be the sort of hardest thing to catch, because you would think, okay, I still have this pointer to the object in A, right? So A clearly points to this object. So no matter what I do with account, I do have a pointer to this object in the variable A, so it's not garbage collected. Who cares that I am going to null account? So where are things going to crash? Not here, right? Because A is not now, not even here, because I can get A dot with draw. It's still in that object, right? Think what happens? Into this variable, you store this object. In here, what does this mean? You create a function and you store it in another field with draw, all right? And now this will point to some closure. You call it, and that's fine. Now we want to call it again. A succeeds, not null, A dot with draw succeeds. It still points to this closure. But something is going to blow up. So what is going to blow up? Actually, I am creating new objects. At least that's the semantics in LuaN164 that each time you see the table literal, a new one is created. That's true even in Python except for these stupid default parameters. Oh, I see, I see. That's what you meant, right? That, okay, okay, okay. So, right. So that is true. I'm sorry. Account is, we think of it as a new object each time, but it really is not. It is just a name that we have been using here as I'm sort of handled to where the implementation is, right? And somebody nicely cleared it and we have a problem, right? At this point, we'll get a null pointer exception. So how do we fix, okay? We'll create a cell for this pointer essentially that the method itself now becomes a special kind of method. It receives as an argument what is called typically as a receiver. It's a receiver because the original object during the paradigm started by saying everything is an object and it responds to messages sent to them so objects are receivers. So exactly that's what we'll do. We'll introduce self and here is how you do it. You need to give this method an extra parameter and now you see we have broken this dependence on this object. Now this dependence to the object needs to come through this argument self. And this is correspondingly rewritten and it will all work well because A1 points to this object and yes, account has been nailed, but we are passing this A1 explicitly. So these two expressions which exploded before now are happy. If A2 is another object, again the call is happy because we pass it in. So now we clearly want another sugar, right? Because who would like to pass these two explicitly, right? That's not good. Oh yeah, you could make a mistake exactly and pass two different arguments, two different values. Yeah, the receiver would be different than intended. So what sort of sugar would you suggest? So could we somehow, well that's an interesting question now. We have a dot and perhaps you would like to keep using the dot but without having to specify this. So you would really like to write A with draw. Can we pull this off? Yes? How? No? Why not? So this would be probably nice for cultural reasons because we are used to A dot being a method call. Okay, so we would define a constructor which presumably would create an object, right? And right, so essentially we say we would create a special object. What would that object do? You somehow want to hide in that object the process of taking some self-value and replicating it. Maybe you could pull it off, right? So how do we do it? So can we somehow overload the dot so that we could somehow pass the argument explicitly? Right, so the proposal is to see that if we know that A1 is an object, okay, we would then somehow change the function call that is right there and give it an extra argument. So let's see. So I'm not saying it's a bad proposal. Let's talk about it because there are interesting implications. So we would have this construct here. Currently we have this construct, right? We have dot id. That's all we have for dot id. We do not have a special dot id call, right? In fact, we could write calls currently with p dot f. You can take the value, put it into as many parentheses as you want. It's a closure of what you return and then you make your call. To support what you are saying, we would do something like e dot id args and now we have a difference in tactic construct and the parser now would distinguish between them, right? And say, oh, I see now the parentheses for the arguments need to be right there. Presumably, it must be an object, okay? And so what problems do you see? Do you see any ambiguity? Clearly we would like to keep this for accessing fields and now we would also add this for a call and this call would be translated in such a way that this value would be also passed as this implicit first argument. So you should now see the trouble. This is often the trouble that you see only once you type in the grammar and the parser will tell you what. Yeah, we would need to, there is no way to distinguish and what we would need to do, we would say, we would need to adopt the convention that whenever we use this, this must be an object. I see. So maybe then at runtime you would need to make the distinction and if it's an object, you would pass that argument, right? That's right. So we would need to carry some sort of type marker in the dictionary to distinguish a runtime between dictionaries that are dictionaries and dictionaries that are objects, right? The programmer could be made his life easier by saying, we'll give you a special constructor for objects. We would be a special dictionary. And now it becomes sort of too many constructs with various interactions between them. So at some point you say no. And of course there are languages that didn't do it that way. JavaScript has objects but they also have this function object. So you have really two different flavors and that's enough to cause confusion. So see, this is probably not a good idea. So what we'll do instead, we'll introduce this notation. And this is like a dot except when it's a colon then we are going to put this argument implicitly here, right? Now how are we going to desugar it? So the syntax is E colon ID as before. Now we do need to have these arguments here, right? Because this only works for calls. This by itself does not make any sense, right? You cannot put it into a bigger expression and put ID. Or does it make sense? It doesn't, right? The colon will only work for calls or not, okay? So think about it and tell me. So this is a construct where we introduce colon for these method calls which will receive an implicit argument. Here I'm saying let's make it more general. E colon ID would work for objects, whether we are accessing methods or fields in them. Would this work? Oh, I see, okay? So you are saying this construct maybe is not such a bad idea because the result would be the function itself, okay? It's the first argument bound and the rest still free. So after that you could call it as a real function. Yeah, that's cool actually. I don't know how to implement it easily. Because what if that function has, say, five arguments, right? Now you need to somehow manufacture at runtime a function with, well, yeah. So it has five arguments plus self. So you somehow bind self, need to wrap it in a function. Yeah, you could do it but I'm not sure it's worth it. C++, by the way, has this notion of you can get a pointer to a method and it's one of the reasons why the manual is so thick. Okay? Okay. So why is it not so easy? The problem is I want to get ahead so that we cover the interesting stuff but perhaps you can quickly answer the question. So what your proposal is, we have that, right? And the way we'll translate it is that the parser will say, oh, I see ID is foo so we know the name of the function and we can presumably look it up in the definition somewhere. So we know it has five arguments and so we'll wrap it in a newly created function created in the parser. I can see two problems right away. So in a language like Java, when you see this, you would see something like x foo and now you see this call to foo. You would know in Java some more information about x. What would you know? The type of x. You would know it belongs to class capital foo. In a language like Python, JavaScript, Lua, what do you know about x when you see this call? You know nothing, right? So you don't know what class it could be at runtime. In fact, at runtime it could be one class or another. You don't have any static information in the compiler. So you cannot really look up foo because there could be a million classes in your program that contain foo. And so that's the problem of compiling dynamically type languages that the fact you don't know what types these variables will have at runtime really limits you. We look more at that in a week after the exam, but you see why this would be hard to compile. Okay, why not do it at runtime? Because typically what we do with the parser will translate it into create a new function at compilation time. Now you could perhaps delay it. Yeah, so you could have some runtime compilation. And when you see the value of x, you would know its type. Yeah, then you would know foo. Then you would do some reflection and ask, how many arguments does foo have? Then you would create a wrapper. So, right, at runtime you could do it. But now we are complicating the compiler interpreter because we are delaying the actual process of compiling this foo. And you would need to compile it each time, right? That's clear that each time this foo is called you would need to discover the type of x and wrap it. Not impossible, just a bit more complex. You could solve it by allowing multiple arguments and just grabbing all of them and putting them in. And so now you see how these various features, the manipulation of multiple arguments, examining functions with reflection and asking how many arguments it has, what type it has, how these are metaprogramming constructs that allow you to build these features. So, but let's go, oh, one, all right. So, what is the problem with the current objects? The problem with the current objects without asking you, you know, is that you have this object, it carries its fields, and it carries with itself all the methods. So if I have a thousand objects of the same class, they will each have copies of all the objects, the methods they have. The methods themselves, the code may be shared, likely will be shared, but the fields for the methods will be there. So how are we going to deal with the problem? Okay, we could have a master table, so now it looks like we are converging to the notion of class, right? So, we could do a class, but before we do that, let's see what meta methods are. Meta methods are a general construct in Lua, but also other languages for implementing other features. What do they do? Well, when you want to read a field in a dictionary and the field is not there, so the key that you want to read is missing, you're not going to get the error right away, but the interpreter will first look at a special sort of field in that table and say, okay, before I give up, let's see whether I have a redirection to another table which might contain that field. So you now have a delegation sort of, okay? And the way it is done in Lua, for reasons that are not completely known, the way it is that if you have A, here is your dictionary that A points to. You set up a meta table, let's sort of call it a MT, a special hidden field that the programmer cannot read. Okay, now you create a new table index which will map into this here. So this is what B points to. All right, so what we have established here, we registered in the dictionary A a table which contains just one key underscore underscore index and points to another table B. And now if you do something like A and a key and key is not here, then the redirection will take us this way in here and if key is found here, then the value here, one would be returned as the value of this expression. Pretty simple. The only straight thing is that we are not keeping this index variable in the dictionary itself, but we are keeping it in a separate dictionary. Can you tell why this is so? Because an alternative design could be A points to the table where we have all our data, now we'll put the index here and this will directly point to this B table into which we are redirecting. Why not this design? Well, one thing is that the meta table data should be shared. So we could have just one instance of this, shared among all instances of, well, if there are many of these and they belong to one class, they could be shared. So that's one. What is another benefit of put? Well, the first one, imagine that you have many copies of this object. They are sort of instances of your class. And it is true that each of them stores only the index variable, but as it happens, and I should have said that, in Lua, you have other special underscore, underscore variables that redefine the behavior of dictionaries in various other cases. And those you may want to override as well. So these meta tables could have multiple entries in them, and then their size would grow a little. So therefore sharing would actually save you something, right? But think of it could double the size of some objects or triple. So that's significant or the same. Assuming that this empty is also just a field except not accessible to the programmer. Another point might be that you are not inserting the underscore index into the table. Maybe that's what you wanted to say. Okay. Why? It might. We'll see it in a second. So let's reevaluate then whether it will work. Well, but what I wanted to say is that by having the underscore index in a separate table, you are not putting it in the namespace of the dictionary. And so there are no clashes with the keys that the programmer may introduce. So let's do prototypes. How many people heard of prototypes-based inheritance? Yes. Yeah. If it fails. Right. You could say that you simplify the concepts of the language because you do not have a notion of a class and a separate notion of objects, everything is an object. And so sort of you have the notion of half the number of notions in the compiler. So if you really want a simple language, then this is it. That's underscore empty doesn't clash because that's a sort of special field that is not accessible to the programmer. You could accept there is a bunch of these and you may want to invent them as the language evolves, right? And so you have sort of one fixed two actually methods. You can set meta table and read meta table, set and get. And that's it. That's the only way to access the empty field. But the underscore fields can grow as the language evolves and gives you more features, more metaprogramming features. Okay. So how do we want to set it up? So we have one object, another object. Okay. And this would be our prototype. And this would be our object instance. And somehow this one will delegate to this one here. But how do we set it up? Clearly, we are going to use the meta table to say if we cannot find something here, then let's look here. And we need a meta table with the underscore index. We'll point here. Okay. So this is the meta table, not quite a visible field. But still you register the meta table and this is the underscore index. And when we want to read something like a withdrawal function, it doesn't exist here. But the delegation will find the withdrawal function here. This points to the lambda. And the code looks like it actually found it over here. That's the simple part. How about sharing more than just functions? What if we have objects with a bunch of constant fields? Like constants 1, 2, 3, and so on. Where would they, where would you want them to be stored? So imagine you have a graphics library which has coordinates, x and y, sizes, width and height, colors, alpha, and so on. Presumably, each time you create an instance of this object, it has a bunch of default values which you might change, but perhaps often you don't. Where do we want to store those things? In Java C++, each class has a notion of a constant, right, which presumably is the same across all objects. Where do we want to store them? Do we want to store them in each object separately? So how would we do that? Okay. Yeah, please. Okay. So the first half of the answer is trivial. Clearly, those constants will be stored in the prototype. And on an individual basis, we are going to store those values in the individual object. So maybe the color by default is white, but some of the objects will overwrite it. Now, how are we going to make that possible? How are we going to overwrite it? What mechanism are we going to use to say, okay, for this object, the color is not stored in the prototype, it is stored here. We somehow want to do it in an elegant way, ideally for free. So I want people to think about the mechanism with which this will happen. Okay. So if we have an instance a, and I write something like a dot x equals a dot x plus one. And if before this statement a does not have x, but x is only here, maybe it has value 12. What will I have after that statement? We'll have a key x right? Because this read is going to, through this delegation, read 12. Compute 13. And this will be a put, which doesn't use delegation. It will just install this key x in here. Well, I should say x like that. And store it there. And that's the mechanism how, when necessary, when you want to override values, they just somehow get moved from the prototype into the instance. So you get it for free. Of course, there is various notions of danger associated with this. But you get something for free. Please. Uh-huh. Well, if you delete the prototype, what happens? That would happen. But you want to set it up in such a way that when you create an object, it's not easy for you to delete it. How could you delete it? Yes, the user of the object would have to go and disconnect the meta table, right? Essentially unset it. So break this connection. Or you would need to go into the meta table and break this link. But short of that, you still have a link to your prototype. Now, you could mess up the prototype. You could somehow obtain its pointer directly and change the value here. You could remove the methods from here. All this could happen. And it's often used for programming purposes in practice in languages like JavaScript. Whether it's a good practice, you now need to say proceed with care. And maybe sometimes the means justify, the goal justifies the means. All right. So now here is something interesting. So here is actually the constructor for object called new that does set up the link between the instance and instance and the prototype in some interesting way. This is a little fragment of Lua here, which I'll explain. And it's simple. If this is nil, then this is false. And therefore, this becomes the value of the expression. So again, if this is nil, then a new object is created. Otherwise, O is just copied over here. So you could call it like this. To take a paper and pencil, if you cannot visualize it without it, because I always need to draw it. And see how they set it up. You see something interesting here in how they set up the meta table. I know you don't feel like drawing it, but you will eventually draw it on the exam or on the homework. So you might as well do it now. I really recommend drawing it because multiple, not multiple inheritance. So far, we have just object and a prototype. Turns out that inheritance will be set up elegantly on top of that. So it's good to understand what's going on. You could start by asking, well, in this piece of code, how many objects are there in flight? How many are we creating? One, two, three. So clearly, here is one object. Here is maybe another one. The account, don't forget, that's an object, presumably created before. So assume before we have done account balance zero. So we have this object here. I discover why PowerPoint crash last time. And let me show you something interesting. If you enable the pen by going here, can you see the pen? Then it misbehaves. You see how it goes to the next slide. Actually, I probably should not try it again. But if you do it through a right click, and you select the pen this way, now it erases without this special effect and doesn't crash. Go figure. Sort of learn these workarounds like analogous to don't step in front of the bus. All right, so how do they hook it up? So what do we know at the end of this short sequence, at the end of creation of a new object? So clearly what we are doing, we are creating a new object here to be distinguished from this prototype. We want a certain setup, right? So let this be this object. Let the prototype be here. So would A point to this? Yes, right? So A will point to the return value. What is the return value? It's either this fresh object here, which is not the case, or it is what was passed here and it was that. So A will point to this. Okay? Now, we are going to register a meta table for this object, which was passed here. What is it? It's self. What is self here? It's account. So what would be the meta table, actually? Where is the meta table created? The one that stores this underscore index. So any ideas? What's the meta table? So they are abusing or perhaps carefully using the prototype itself account as the meta table. After all, it's a dictionary. So the meta table here is going to point to account, right? Because you make this call, self in the new is going to be that. So account is bound to, let me make it nicer, self. Okay? So this is the registration. This is the meta table, the registration that is created in here. And now what are we going to do? We are going to create an index key here. Where is it going to point to itself? Okay? So where would the method withdraw be stored? Is it going to be here or here? On the right, right? So the withdrawal would be here. So this is the wiring that happens when you set it up, when you create an object. You notice that this here might be redundant. It does the same assignment each time, but you need to do it at least first time that constructor is executed. You see any problems with it? Does it work? You like it? Do you don't like it? Seems to be okay. It's kind of elegant how you set up inheritance on top of the meta table mechanism. Now inheritance, we talked about why you may want to do it. And I'll let you draw the setup that we want here, but essentially we would now like to have two prototypes and an instance. And if one prototype does not contain the field or the method, it will already react to the next one. And I think by now we understand it quite well. And let's see how we would use it. Here is a constructor. I actually need to check whether it does the right thing. But the important thing is here that here we have our withdrawal method that does a little bit more, right? What does it do? It now does error checking, something that we didn't do before. How are we going to create this inheritance? We would like to have a normal account object and now the one with the special withdrawal method. It looks like people are getting tired. So let me just show you the way it's done. You create a normal account. You call it a special account. At this point it's just an instance. But now you can create one with a special limit, right? We are adding a field and it's created here. And now it has a different behavior. So what do we have here? We have account, which is the master, sort of the top prototype. Now we have a special account, which redirects to this. And now we have s, an instance of that, which redirects to that. And you can convince yourself that this just works. But I want to get to something more interesting. We talked about sharing multiple inheritance, not so interesting for now. Privacy. So let's talk about return to the privacy goal that you had before, okay? What did you say? We want certain privacy or we call it protection. That protection is not in the sense of hiding your social security number. We want protection from a different scenario. We want to support large programmer teams. So can somebody suggest a scenario why you may want to protect your implementation from others? Can you suggest some bad scenario? Okay, we have one hand. Can other people see why bad things can happen? Somebody else for a change, okay? Perfect. I see. Exactly. So the scenario you said was essentially this. Programmer A implements an object. Programmer B now uses object, but it relies on some internal representation in that object. One that the programmer A didn't expect anybody would use. Now programmer A says, I'm going to optimize the hell out of this object. And she will change the optimization, not knowing that somebody relied on it. Maybe B was not supposed to do that. And now the program crashes and perhaps tests even don't catch it, but it crashes on the customer's machine. So we are sort of viewing these two programmer teams in an adversarial relationship in the sense that one wants to really hide the implementation from the others, not because you don't trust them, but because they should not do things that may change in the future. And so how do other languages deal with this issue? What are mechanisms in Java to make it possible for you to hide that? Or they have just spoken agreements about not touching certain fields. Does anybody know what the constructs are? The idea of private protected essentially saying it is here, but you can only access those fields from inside the class. Nobody from the outside can. And this is exactly the little extra construct that you add so that no user can rely on it. You don't really want to hide the information from them because they can read the source code, but you want them not to build code that relies on that knowledge. So packages are. Packages came later partly because classes now sort of were too small to hide logic pieces. And people said, sometimes you need to have multiple classes and packages came up. Right. But you can think of packages as classes at a higher level of granularity. Well, excellent. So let's see. And this is exactly the point that Lua people will tell you. This is for small programming, not for large teams, but it may be possible to hide the implementation in a way that you actually prevent people from using what they should not be using. So how do we do it? Okay. So we do have almost 10 minutes. So let's figure it out. How would you actually support objects in such a way that you can safely hide fields to the point that you could not really through any means read out the value of the field, say the password or anything. Well, so the suggestion is to use a protection bit for every field. But now we are sort of giving up. We are saying the OS people have to help us. So I'd rather not do it if we don't have to. So no extra construct is needed. Lambda's and dictionaries are enough. We may need to rethink how we are doing it. Sort of objects as tables may not be the right approach. So let's hear some proposals. Okay. So, okay, you were reading ahead. So you know how JavaScript does it. And essentially that's the idea. Do we have other proposals? I'm sure there are more than one. Right. Essentially, let's assume we don't have inheritance for now. So only the class can see it. So the distinction between private and protected. Let's forget about that for now. And yes, you want to be able to exit from the class. So the author of the class should be able to see it, but not the user of the class. Okay. So we'll hide it somehow in closures. But how exactly? Do you want to scribble down a little design? What will the object be? A table? A closure? Closure of tables? A table of closures? A closure of closures? I'd say the design I'll show you is pretty clever. But let's try to reinvent it. So we want to be able to, okay, so let me put a stake in the ground. What do we want? We want an object on which we can call some methods. The object can have fields, so it does carry the state with itself. The methods need to have access to those fields, of course. But from the outside, no way how you can access those fields. And I'll make it harder. Imagine that objects do have the ability to enumerate all the keys. Right. We assume that, sorry, objects, dictionaries. Right. Let's assume that we do have a construct on dictionaries that will return a list of keys. All of them. It's just a dictionary. Dictionary is a dictionary. Right. We are using dictionary to build objects, but the dictionary has no notion of private. So you may want to have a dictionary, which, right. So if you implement an object as a dictionary, be careful that whoever receives it now could iterate over all the keys and figure out what fields you have inside and use them to do something that they cannot do across their procedural interface, across the methods. So let's think about this a little. So it needs to be resistant to this sort of attack. Let's start here. That's okay. Okay. That sounds great. So let me reiterate if I understand correctly. We'll have methods. We need those, because you need to call them. You need to put the code somewhere. Those, all of them will have access to one dictionary, which will be the object. It will store the field. The methods have access to that, but only the methods do. And since you cannot go to the method and you cannot walk its environment and read the fields, you cannot get to the dictionary. Okay. So it is stored in the environment of those methods, the closures, but not elsewhere. Okay. Right. So I think this is very similar. I think the difference is that you could store these fields directly in the closure sort of as local variables of the enclosing function, but you could put them into a table. Probably ends up being the same. Maybe you save some memory if it's a dictionary, because the closure will keep the entire environment, whereas the dictionary would sort of be perhaps more compact, could be more efficient, but logically it's the same idea. I would think that. And what's stored in that table? The functions are stored in the table? All the public fields are stored in the table. Right. Okay. So that's essentially it. This is what they do. So here is our new account, the constructor. When you call it, it creates a new object, how it creates it here. It has a local variable self. And now the functions we draw can refer to it. And the object itself is this dictionary here, which maps keys to values. And that's it. So this is what you guys had in mind. And I was wrong that if you store it in the object that the environment, the frame can disappear because there is still the self here, which would keep that environment alive. So just one thing to comment on. Look, we have we draw twice. How does the parser or the semantic analyzer deal with this? What does this we draw refer to? It refers to this function, right? What does this we draw refer to? In which environment is it looked up? Is it the same we draw? Is this referring to this? No. So what happens with that we draw? It might be sort of confusing that we look at we draw equals we draw. What does that mean? So the we draw here is not really a name of a variable. You can think of it if you know Ruby as a special thing, right? There's a symbol. Really it is turned by the parser into a string and used as a key. Or we could, right. We could, the suggestion is to the reason why I did it and now the eraser. Don't crash. Instead we could have put here directly lambda v and the body comes here. We could. I think I stole it from nice little textbook and that's how they did it. I guess you can see more compactly that at the end you return this dictionary and you can see what's in it so it's perhaps more didactic for the purposes of the lecture. So I think that's it. You use it like that just like before. Actually you don't use it like that. This is the interesting thing, right? Notice that, right? Why are we using it this way? I completely forgot about that. So this is kind of cool, right? That you don't need to carry the receiver now. You don't need to de-sugar it to passing the receiver. This is now not a column. And you do that by having this extra table here and the self-packaged that way. Isn't this nice? So the dictionaries and closures together does really give you a lot of freedom. So now you're asking perhaps how does it play with inheritance? Let's take it offline since I don't want to keep people. But how to combine it with inheritance? I don't know. Could be a great exam question. Not for this midterm. This is not going to be on the midterm. And I don't know the answer to this.