Sunteți pe pagina 1din 5

[music]. In the previous segment we saw four rules for our subtyping relation which are allowed.

In this segment, I want to investigate a fifth rule and see why it might not be such a good idea. So, so far our subtyping rules let us take a record type, forget some of the fields, and reorder the remaining fields. That's all it lets us do. So here's an example that it's not quite able to handle yet. So, in this example I'm going to have some records that represent circles. A circle can be represented by it's center and it's radius. Now, what if for the center I used a nested record that had a point, an x coordinate and a y coordinate. Well then, a record type might look like this argument c to the circle y function. C has type record with two fields, center and r. R has type real. Center is another record type. It makes perfect sense that a field of a record could refer to another record. And that inner record has an x field and a y field. So this function, very simple, just takes a circle and returns its y coordinates. So, how high is it in the plane? Okay? So, all I need to do is return c dot center dot y. Take the record c, access its center field with c dot center. That gives me back a record. Say, dot y on that get back a real. And given the type of c, this will never fail. Now what I cannot seem to do. I can't, with my current rules, is call circleY with this sphere value. What's a sphere? It's something that also has a center and a radius but it lives in a 3 dimensional environment so that inner thing, the center has an x coordinate, y coordinate, and a z coordinate. So, same sort of nested record, except the thing in the center field itself has an x field, a y field, and a z field. So I could make such an object like this. This is the sphere centered at x is 3, y is 4, z is 0. It has a radius of 1. And if I call circleY with this, if I

didn't have a type system, this would work just fine. I would get out the y coordinate. I would get 4.0 back. But in my type system, this only works if the type of sphere is a subtype of the type of c. So, what we would need is that this type where we have an x, a y, and a z inside of the record in the center field is a subtype of center of x y. And you see there. So, I have the same question here and you might be thinking this is fine. I have with subtyping, I can do this. It turns out you can't. What we have to ask is, is this type on the top line a subtype of this type on the bottom line? All width lets you do is drop fields off the record. So we can drop the r field or we can drop the center field. But our width rule does not let us go into a field and use subtyping there. So, what we see is we just forgot a rule, right? So, let's just add a fifth subtyping rule. This rule has a name. It's called depth subtyping, and it's a little more sophisticated because it has an if then. It says, if ta is a subtype of tb, then you can replace ta with tb, in a record type. As you see here, after the ven. It says you can go into some record type Find some field that has type ta and replace it with tb. You can do that, as long as ta is a subtype of tb. And so, if we had this rule, along with width subtyping, now we can get the subtyping relationship we need for our sphere records and our circle records. Because we'd be able to use this rule to kind of go into the type of the center field and then the width rule, to drop the z out of that inner record type. So, depth subtyping makes our other rules more powerful by letting them be used on record fields. And that is enough, going back to the example here, to pass sphere to circleY. So, it sounds great and we should add it to our language. Right? Wrong. So, it's all nice that our new subtyping role lets our example type-check.

But when you're evaluating whether rule is a good idea. By evaluating I mean judging, not evaluation like we've meant in this course. When you're judging a rule, you don't get, just get to try it on the examples where you want it to work. You also have to make sure that all the programs you do not want are still forbidden. See, it's not worth making a type system more flexible if it breaks soundness. If it allows programs that, in our case, let you access missing record fields that try to read out a foo field from a record that doesn't have a foo, or a z field from a record that doesn't have a z. And unfortunately, the rule I just showed you, that depth subtyping rule Is unsound. And all I have to do to prove that to you is show one example where with the rule of the program would type check, and when you run that program, the bad thing we're trying to prevent would happen. So, here's an example and involves mutation. I love to pick on mutation. This is another opportunity where mutation, messes us up. So instead of circle y, here's a function setToOrigin. It takes in a c of the exact same type as circle y[COUGH] record with a center field and an r field. Where the center field itself is a record with an x field of type real and a Y field of type real. And what it does is it moves the circle to the origin. So it leaves the radius alone, but it updates c.center to be x equals 0.0, y equals 0.0. This is fine, I told you records had mutable fields. We love to mutate things, right? So this function is perfectly reasonable. And it updates the circle, the circle. So what would happen if I call this function setToOrigin with my sphere? Well it's going to mutate that sphere. In fact, it's going to mutate in a way such that it's not a sphere anymore. It's going to change the center field to hold a record that does not have a z field. This is a very bad idea. After I call setToOrigin of sphere, the type I gave to sphere is fundamentally wrong.

The type I gave to sphere claims that in the center field is a record with a z field. And there isn't anymore. So on this next line when I say, sphere.center.z, this will typecheck because sphere has a type I gave it. So it has a center field. That center field has a z field. And if you actually try to run this program in its entirety, you'll get stuck right here because there, there is no z field in the record that you get back from sphere.center because of the earlier call To setToOrigin. And the only typing rule we added, the one that's to blame, is this subtyping rule here, depth subtyping. You just can't do this. You can't let a record type field change to a supertype turning ta into tb because that lets functions like setToOrigin turn spheres into circles. So, to repeat the moral of the story. If you have a language with records or objects, because objects are things that have a bunch of fields in them, like instance variables with getters and setters, depth subtyping allowing subtyping on record fields is unsound. A lot of people forget this, a lot of people don't, never learn this, never realize this. They think languages should support this and they don't. If you have getters and setters, you cannot allow the type of a field in a record to change to a supertype or to a subtype for that matter. But here's the neat thing. If fields are immutable, if you take a more functional approach and don't allow setters on your records, then depth subtyping is actually sound. I haven't shown it to you here but I promise I'm not lying this time. Alright? So, this is yet another benefit of outlawing mutation that it turns out that when it comes to records, you can choose any two of the following three. You can allow setters, you can allow depth subtyping, and you can have a sound type system. You can have two of those three but, as we saw on the example on the previous slide, we can't have all three. So if you want soundness in depth subtyping, why not get rid of the setters? But if you wish to choose a different two

out of that list, I suppose that's a matter of personal preference. In any case, subtyping is not a matter of opinion. If you do have setters and you do want soundness, then you cannot have our depth subtyping rule that we showed in this section. (End of transcription.)

S-ar putea să vă placă și