You are on page 1of 5

[music].

We're now going to study a couple OOP concepts, that you don't need for your homework assignment, but are important concepts, and we could ask on the exam, and are just worth knowing about, and in this segment, we'll discuss multiple inheritance. So we've seen the basics, we've seen inheritance, we've seen overwriting, we've seen dynamic Dispatch. Now let's think about, would it be useful and what would it mean, for a class to have more than one superclass. So what, over the next couple segments, we're going to see multiple inheritance, which is where you have exactly that, we'll see that it's useful but has some problems, C++ is the most well known language that does support Multiple inheritance. Then we'll study Ruby-style mixins, which are less powerful but have fewer of the problems, And then we'll study interfaces like you see in Java or C#, that are even less powerful and have even fewer problems. So you get kind of a range, and these things are different from each other and make sense in different settings. So here it's just multiple inheritance for now. So the idea is, if having superclasses where you can inherit method and override them is so useful, then why limit yourself to just one? And what we'll see a little bit in this segment, is that there are some awkward semantic issues about what things should mean, and how multiple inheritance should work. There are some other things I won't discuss, but may as well mention, that it does make static type checking more complicated, and it also makes Implementing OOP languages efficiently more difficult but we will focus here on just a couple of the semantics questions. But before we do that, let's just make sure that multiple inheritance is something we might actually want, that was actually useful. And I think it is fair to say that there are situations where it is useful. Now, how many? That's a matter of what kind of software you're writing. But let's just look at some code here, like I have here in this Ruby file.

It's small example, so I can go through it in just a minute or so. But suppose I have a class point that has getters and setters for x and y, the x coordinate and the y coordinate, and a little method for the distance to the origin. And, as we've seen before, a very natural subclass for this, would be a class color point that maybe adds a getter and setter for color field, and maybe even has some method that adds dark to the color. So if you call darken, and the color is currently grey, you get dark grey. If you call it again, you get dark, dark gray and so on. Okay? We might also take this class point, and subclass it with 3D point, as we discussed before, this is very controversial. But you can create a subclass, that adds a getter and setter for z, and overwrite the distance to the origin method. Okay? Especially if you spell it, oh I guess we spelled it incorrectly in both of them, but it doesn't matter. And finally, what if we now wanted a color 3D point? So in a language with multiple inheritance, you would just write something like this. You would just create a class colorPt3D that, you know, had superclasses, colorPt and pt3D and, of course, you could add more stuff if you wanted, but in this case actually all we want to do is inherit all this stuff from colorpt, and all this stuff from 3D point. But you can't do that in Ruby, there's just no syntax for it. You get exactly one superclass object, if you don't indicate one. So in Ruby if you want color 3D points, you end up copying code and repeating things. But there's kind of two natural ways to do it, one way is that you could subclass colorpt, and add the getter and setter for z, and then, override distToOrigin. The other possibility is that you subclass 3Dpt, and add color, and add the darken method. And it's not clear to me which you would prefer, probably whichever one is shorter, but neither really captures the idea that what you want is to have everything from two different superclasses. So there are other examples. For example, if you wanted a student

athlete class, maybe you want to inherit from the student class and the athlete class, that maybe both inherit from some common superclass like person. And then you would get all the attributes that a student has and that an athlete has, and so on. Okay? So, before we go on, let me introduce just a little bit of terminology for how to think about this stuff. And the first thing I want to emphasize is, when we talk about subclass and superclass, we can often confuse each other when we communicate. So sometimes we mean the immediate subclass. A is the immediate subclass of B, if A lists as its superclass B. And other times we mean transitive subclasses, which means that it is a subclass, but it may be because of multiple superclass relationships. So if A is a subclass of B, and B is a subclass of C, then A is a subclass of C, but it's not the immediate subclass, it's a transitive subclass, fine. So in a language with single inheritance, basically, all of your subclass relationships form a tree, and we actually call this tree the class hierarchy. Right? So you could represent, for example, maybe there are three classes that subclass A, B, C, and D, and maybe another class E that subclasses D. So the idea is that your parent in the tree is your immediate superclass. What multiple inheritance fundamentally does, is make the class hierarchy not a tree anymore. Instead, it's a directed acyclic graph, it has situations where something could have multiple parents if you will. Multiple parents in the class hierarchy, and therefore, there are multiple paths between, as you see in this example here, the class Y and the class X. Y is a transitive subclass of X, and there are two ways to show it. You can show that the Y is a subclass of V, which is a subclass of X, or Y is a subclass of Z, which is a subclass of W, which is a subclass of X. And that's where things start to get a little more awkward. For example, suppose V and Z both, both define a method M. Which one does Y inherit? That didn't really happen with our

color3Dpts. Right? But if they define any differently, or maybe they both override some method in X, which one does Y get? Maybe Y needs to override it, what if Y wants to use super, well, now it has to say which super it needs. I'm not saying any of these problems can't be surmounted, but they make your language more sophisticated and more complicated. Here's another situation where it's not even clear if you should do the same thing as the previous point, or something different. Suppose X at the top here, defines a method M. Z overrides it, sorry, Z overrides it, yes, and V does not. Well now, what's the, what, what method M do we have in Y? Is somehow it important that Z overrides it, or does somehow Y get Z's method M and X's because V did inherit it, V does have a method M? It probably should not matter to us, that V inherited it rather than defined it itself, maybe from Y's perspective all that matters is that V has the method M. And then fields, what Ruby calls instance variables, but in most objects program languages can be part of a class definition, get even more complicated. Supposed there is instance variable, defined up in X, should Y have one copy of it? Which kind of makes sense, it's an object, it has an instance variable. Or does it need two different ones? And for that, I thought I'd show you, that actually, both situations do arise in practice. That's why C++, which I'm not going to show you, actually supports different kinds of subclassing, in inheritance for this situation. So it sometimes, you get two different fields with basically the same name, just from different classes, and sometimes you get only one. So in our 3Dcolorpt example, it turns out that we have the situation where point has two sub classes, colorpt and pt3D. And then colorpt3D, if we could do this, would have two superclasses. 'Kay? So, it seems clear that in our 3Dcolorpts, we want to have one X getter, one Y getter, one X setter, one Y setter. We want to have one conceptual field for

the X coordinate and one for the Y coordinate. We don't want two coordinate systems, one from Colorpt, one from point3D, we want one, and that's an example where that's what you want. A short example where you actually want two different copies of instance variable is a little sillier, but I actually find it funny so I will show this to you. In this situation, we imagine that the top, we have the class Person. And it has two subclasses, Artist and Cowboy. These are 2 different kinds of people. Artists draw things, and, cowboys, well, now, if you don't know English, you may not realize this. Cowboys also draw things. Turns out when you pull a, a gun out, it's called drawing the gun. So the same way an artist might draw a picture, a cowboy might draw a weapon. Okay? Now, there's nothing unreasonable about having an Artist Cowboy. This is someone who likes to paint pictures, and be a cowboy and do all the things that cowboys do. All right? But, now it would have two draw methods. And that makes sense, because there, this, our Artist Cowboy sometimes draws pictures, and sometimes draws weapons. But, if both of those draw methods use the same instance variable, say, pocket, because the artist needs to draw a paintbrush out of his pocket, and a cowboy needs to draw a gun out of his pocket. Then for these methods to work correctly, we actually want our Artist Cowboy to have two pocket getter methods. To have two pocket fields, pocket instance variables. And that somehow when we do this subclassing, we, we want to duplicate the idea of having a pocket and for an Artist Cowboy to essentially have an Artist pocket and have a Cowboy pocket. And so there's no general solution to this, we wanted one semantics for 3dcolorpts, and a different semantics for artist cowboys. And these sort of complications are why a number of languages avoid these issues, by choosing not to support multiple inheritance.