Write a Compiler That Understands Types

Unify Multiplication Operator Exercise

Write a Compiler That Understands Types

Lesson Description

The "Unify Multiplication Operator Exercise" Lesson is part of the full, Write a Compiler That Understands Types course featured in this preview video. Here's what you'd learn in this lesson:

Richard provides a brief summary of part 4, including unifying operators, type mismatches, and the unify() function. He also walks through the unify multiplication operator exercise and solution involving the multiplication operator in typecheck.js, showcasing the process of handling concrete and non-concrete types in the context of operators.

Preview
Close

Transcript from the "Unify Multiplication Operator Exercise" Lesson

[00:00:00]
>> Richard Feldman: So to wrap up, summary part four, we started off talking about unifying operators and just like the very basic. We should get two type mismatches if we call the multiplication like the time sign and the two things on both sides of it are definitely strings. We talked about type mismatches and how the only way you can get type mismatches so far that we've seen is through unifying, vacation and that's also gonna persist.

[00:00:22]
If we're just doing like, you one constant side to another, there's no real way to get a type mismatch no matter how many of them you chain together. But as soon as you start getting multiple constraints into play, that's where type mismatches come up. In other words, like you're calling unify on the same number more than once, or the same type ID more than once.

[00:00:37]
That's where the first time it can set it to one concrete Or something that becomes a concrete type. And then later on, you attempt to unify it with something else that's a different concrete type and that's when the trouble starts and that's when the type mismatch happens. And then finally, we went and looked at the code of the unify function itself to just really see like, conceptually, yeah, it's kind of like the types are identical but really, it's own thing.

[00:01:00]
It's like those specific branches that do these specific things under these specific circumstances that's really unfortunately. The best way to understand unify is just to kinda look at that code and just remember or even step through in your in your mind. What branches are happening when
>> Speaker 2: in unify with the case where we have both a and b as null.

[00:01:20]
Richard said that it's not important that we simulate a to b or b to a, Can you speak a little bit more about that?
>> Richard Feldman: Sure, so this was like right here, away that you can tell this that this is true, so the question was, at this point, we are sym linking a to b, right?

[00:01:38]
If a was null, then we're Okay, cool set A, to be a symlink, A is symlinked to B. If you get down into this branch, if B happened to be a was not null and B was null, we unify it and come back here. So a way that you can think about this is, let's just like walk back through this scenario right here so everything's null.

[00:02:00]
And right here, we're like, okay, I similarly this is the sibling a to be right like we unify these two and we said that I D, 0 is now selling to one. What if we instead had like done the reverse and said, like I wanna symlink 12 so let's pretend that this is still null I'm not gonna like change the slide in real time, but pretend this is null.

[00:02:19]
And then The next thing we do is we unify this one and we say that's a string well, when we're going through and unifying this two string, we still do have the information in the database. That prior to doing that, this thing was sim linked to this other type And when we're going through and resolving what we would be unifying that string against is like we would have already traverse that.

[00:02:44]
What we'd end up with is we're now in the branch of unify where we are attempting to go through and unify this with string, so that's like one of the two type IDs. And the other type ID is gonna have gone through the resolve and compress thing, which is gonna end us up back At zero.

[00:03:00]
So after you follow that symlink, like, again, pretending that symlink is down here and this one is null. We're basically saying okay, unify whatever this thing resolves to with string, and what that thing resolves to is a symlink to zero in this hypothetical scenario. So what you end up with is basically like, you're still unifying string with zero, and you're Basically gonna still end up with one of these things that's saying like, I am the same as the other one.

[00:03:26]
And the other one is a string either way you come at it.
>> Speaker 2: Another question is how would unify function work for a node that cannot create a mismatch like assignment are such nodes skipped from unification step or is there some implicit?
>> Richard Feldman: How would it work for nodes that so I think it's important to note that at this point, Unify only knows about types, so Unify actually doesn't like.

[00:03:49]
What we give it are these two IDs so we give it the purple numbers it actually has no idea what node that came from it could have been an assignment. It could have been a number could have been a string, could have been a function, really, it has no idea other than that.

[00:04:04]
Like, it knows what this type ID is, and it can access the database so it can go ask what that type is. But basically because we have this separate phase, like, before then, where we're going through and saying, like, actually even further back. Where we're basically saying, kay, this is the phase where we know which things are assignments, which things are constants.

[00:04:21]
And then, as we go through and assign these numbers and put them in the database, and then start connecting them up and running unify on them. Like right at this point, unify is like, okay, yes, we still have these over here, but unify never sees these unify only sees the numbers and.

[00:04:40]
The relationships between the numbers that are represented in the database so the sum total of what unify is able to access is right over here it has no idea about any of this stuff. So I guess the short answer is basically that that can't possibly affect Unify because it just doesn't even have access to that information.

[00:04:58]
Now, we can go from node to type ID because we write down the type ID in the node but the reverse is not true we don't connect the type IDs back to the nodes. If all you have is a type ID [LAUGH], you're stuck in types land, you can't get back to two nodes if that's all you have, alright, with that in mind, let's hop over and do some exercises.

[00:05:18]
>> Richard Feldman: So we're off to part four now once again, you know, parts four, five, and six are all just going to be doing type check.js so let me cd into that and run our tests. As usual, we have test failure and let's go take a look at how we might fix that got a lotta other type checking stuff here, two right here we are, okay.

[00:05:42]
So this one is just all about the actual multiplication operator, so this is gonna be a relatively quick one, just a five minute exercise. Basically, we're just gonna do exactly what we did in the slides in the multiplication case. We have discovered that we have two operands, as I know, like the two things on the ones on the left, ones on the right, and we've already said, Okay, I'm gonna make this concrete number type.

[00:06:06]
I mentioned like, two sections ago that although for our purposes, for like, teaching in Slides, it's pretty convenient to just say you can just put a number directly in there. This is one of those scenarios where it's okay ,well, actually, what I want is that type ID and so rather than make a bunch of edge cases, we're just gonna go ahead and create our own number type.

[00:06:25]
And if you look at the implementation of this thing, it's basically like, just give me a new type ID, and I'm just going to put concrete right in there, and now I have a type ID for that concrete thing. You never do this in a production compiler, because this is totally wasteful.

[00:06:35]
We're just, like, adding database rows just to write down string, over and over, and they're all getting different IDs instead of hard coding one. But again, this is not a production compiler, so that's the most convenient way to get ourselves a type ID that guarantees points in number without having to pre-populate the database of constants and stuff like that.

[00:06:56]
Okay, so that's our number type ID and then basically the conditional that we wanna do here is take a look at the left operand of the node and also the right one. And if either of those, sorry if they are both concrete, they know if either of them is concrete, it must be a number, because those are the rules of the asterisk operator.

[00:07:16]
So separately, a thing that we would do is we would say those two things need to be equal to each other. That distinction can matter if you have a polymorphic type which we don't for our operator we're saying this is hard coded concrete number. So really all we need to say is left needs to be number and right needs to be number.

[00:07:34]
Otherwise, if they're not concrete, then that's fine, we can just unify the non-concrete type with number and basically say you're null or you're a sibling or something like that, or I guess at this point it wouldn't be a sibling anymore. So you are null, that's fine, but now you were before and now you were a number.

[00:07:51]
And that's not type mismatch because there wasn't any constraint there. And then the final scenario being, you're already concrete, but the concrete type that you are is number. So no harm no foul we will just leave you alone okay, let's take five minutes and work through that.
>> Richard Feldman: Okay, so we have our solutions over here for this one very simple thing where we're just checking to see if we have an operator of star.

[00:08:20]
Then we need to basically just make a concrete type of number, using our little hack here to get a type ID out. And then basically we just have these two scenarios. So left concrete is something that is defined a little bit higher up here, so back up in the top here, before we're looking at what type operator we have, we have this convenient thing.

[00:08:37]
We're like, okay, well, let's go use this get concrete type name thing, which if you go and take a look at this, is basically like, okay, go do the resolve siblings and compress things. So now we have back either null or we have a concrete type Sorry, an ID that refers to one of those.

[00:08:53]
And then basically you say, okay, is entry.concrete not equal to undefined, meaning that like it does have an actual concrete type. Then we can return that otherwise, we return null. So putting that together, what we end up with here is either null or else the actual concrete type itself that's inside there.

[00:09:10]
So not like the object with the concrete field in it, but the actual contents of that concrete field, which means that we actually have a string that we can compare with triple equals and In JavaScript. So using that we can basically say okay left concrete double ampersand is basically saying like okay, it's not null because one of the two possibilities was that we could have gotten it back as null.

[00:09:31]
And if it's not null and it's not equal to number, that's a problem because when we are doing this unification, we expect this thing to be a number and so, it was concrete. But it wasn't a number that's going to be a type mismatch and basically it's just exactly the same thing, but with right concrete if you want.

[00:09:47]
Of course, combine these two code paths and do a little like for loop over over, a two element array of like left and right. That would work too but this, I guess, does give you a little bit more specific type mismatch error message up with this, moving on, okay.

[00:10:01]
So then the other way that we can do this is we can say, okay, and this was a scenario where we knew that it was concrete. This is a scenario where we know that it is not concrete, so this is basically, yeah, this thing is definitely null. You could also have, instead of that, you could have equals equals null, or triple equals or triple equals null, or hey, man, my JavaScript's a little rusty.

[00:10:23]
I don't remember there's some other fancy way to do this, to check if it's null, besides like bang and double equals and triple equals. I think there might have even been a gotta around triple equals I think double equals also checks for undefined. At any rate, point being, this is the scenario where left is not concrete is null.

[00:10:40]
At that point, we're just saying, cool, just go ahead and unify that with number, and we know that that's gonna work out, because it's null. Anytime you unify null with anything else, it's just gonna either sim link it, or in this case, since we know we're giving a concrete type.

[00:10:53]
We know that thing is just gonna end up being number, which is what we want. Then same thing for the right version of that, and then we are good so let's try grabbing that real quick, that's not where I wanna be. There we go, Okay, and bam, all good, you.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now