Check out a free preview of the full Polyglot Programming: TypeScript, Go, & Rust course
The "Enums" Lesson is part of the full, Polyglot Programming: TypeScript, Go, & Rust course featured in this preview video. Here's what you'd learn in this lesson:
ThePrimeagen walks through creating enums in TypeScript, Go, and Rust to demonstrate the extent of enum support in each language. Rust allows enums with many types, including generic, which can be helpful for many typed lists, nullable, and error handling.
Transcript from the "Enums" Lesson
[00:00:00]
>> So I'm gonna cover one more thing that I think is pretty fun which is Enums. Now you're probably thinking Enums those are fairly boring, well rust makes them way more fun, in fact it's so much fun that it did actually change you can do just the greatest things in the universe.
[00:00:16]
And it's really why rust has become my personal like my favourite language is because of this one concept right here, and also the awesome libraries and other things. So first we're gonna go through and I'll just show them in all three languages. Go having the least awesome Enum support and rust having the most awesomeness Enum support.
[00:00:37]
So let's go back to my TS file, what did I call it? TS, Yeah. All right. And so, for this one, this is TypeScript TS Enum, right. Don't do that you only do that with types. And so I can have like foo, bar and baz right? And of course, it has a concrete value to when it's compiled.
[00:00:58]
I assume it becomes a two and TypeScript land. I only assume that I don't actually know that. But I assume they do things to make it very, very nice, right? So this, this all makes sense. I assume everybody understands the Enums. Okay, awesome. All right, and I'm gonna, let's go to go for just a second.
[00:01:12]
Even though I think this it just makes me a little bit sad about their Enum support. So I'm gonna just create a main dot go. You always have to go package main, cannot do that func main. Also just quick side note rust and go have a main function whereas TypeScript has just a main file so, if you ever see why have main functions on rust but not on TypeScript good speakers well, they don't have an entry point the same.
[00:01:37]
All right? So anyways, we take this and we can go like this type, we'll call it GoEnum is an int, and then I can give it the old const to I know this is gonna be great. Foo is a GoEnum iota. You're thinking iota what a great name?
[00:01:57]
Iota is just this auto incrementing item. This is how you specify it. I know it's absolutely ridiculous. But as you can see, it's an int value two just like the other one was an anti value two. Okay, we're gonna, use an Enum and Go when we're building the CLI application.
[00:02:12]
But it just emotionally hurts me that this is what they gave us. But that's okay. Enums aren't a huge part of programming. I don't think anyone's like to upset about it except for me. So let's go back here. I'm gonna copy this TSC Enum, and I'm going to go to that main RS file.
[00:02:28]
And we're gonna just paste it right in here. And I'm gonna call it Rs. There you go look at RSENums. How great is that? All right, so they're pretty much identical to TypeScript at this current point. But they get a lot better. They get so much better. So I don't want to ruin it.
[00:02:45]
And I know I've already skipped ahead a little bit. You could also assign values, right? Foo equals 123, if you didn't want that, you can also use strings in TypeScript if you really, really want it to Go, ridiculous, now rust it's awesome, ours is TypeScript see I already pre planned all these great jokes and observations I was making, it's like I've done this before.
[00:03:04]
All right, so why go over enums? They're very very simple, but this is where it gets awesome you can add types to Enums in rust. Now yeah, I don't want I don't want to look at it yet. Okay, so let's, let's just add some types here. Are you ready for this?
[00:03:22]
Okay, I see everyone's ready for it. All right, so I'm gonna add an i32 right? So that's just an integer. Now notice something right away. Did I specify type on bar? No. Did I specify one on bass? No. But I did put one here on Foo, let's go even further.
[00:03:39]
I'm gonna put this one as a string, you don't have to have the same types on the Enums. So they call this a some type I believe is the functional properness of it, I don't wear tie dye t-shirts. So I am not the best functional person out there, my neck beard just never seems to come in, but I hear these are called Functional Tests sorts of stuff here right?
[00:04:01]
And this allows you to create things that are very hard in traditional typed languages, very obvious example is heterogenous list, right? A list that contains, okay, first item is NRA, the second item is a string, the third item is a number, that's very easy in JavaScript planned that's very, very hard and most typed languages, because those aren't there.
[00:04:25]
They're like non overlapping values at all right? Once a string ones a number you don't, they just don't overlap. Whereas with rust, I can create a vector of this RSEnum, and now I have a list that can be contained of strings of sub vectors. I have I 30 twos and it becomes this really kind of I what I think is a pretty powerful construct right here.
[00:04:46]
So I love this. I just think this is the greatest thing ever. And at first this doesn't seem like it's that big of a deal, but man, you can make some pretty awesome stuff with this. And it's always been the thing that I hate the most about type languages.
[00:04:57]
And so there we go, let's see, where did I wanna go with this? Just so I know what I wanna do. All right, yeah, we can I can even show you how to here. Well do a little example of using them too. So I'll go like this let Foo equals RSEnum, and then I can create a Foo and give it the number five.
[00:05:13]
All right, so how do I get that number five out of here? Well, there's a couple things I can do. The first thing I can do is I can do an if statement, right? So I can go if, let, now this is what what is referred to as pattern matching.
[00:05:28]
If foo value equals foo, right? So I literally am pattern matching this if statement creating a variable on the if statement. So if Foo is an is a subtype of Foo I plucked out the value. So when I look at this type, it's an RSEnum, when I look at the value right here it is an i32.
[00:05:51]
So I've actually plucked out the value. You can do the same thing in a less kind of specific context you can do something called a match. So this also does pattern matching, which pattern matching is pretty awesome. One thing that's super cool about it, is that it can tell you right away, you have a non exhaustive pattern match.
[00:06:10]
So if you're trying to match on all the different values, rust can right away tell you hey, you haven't done everything yet. You need to go and make sure that this thing is working. You can't even compile this program when it's not like that. So then I can put in Foo, and I can put in the value and now I have access, to the value of RSEnum right?
[00:06:29]
And so now I have access to that value, but of course it's still telling me hey you're still missing bar and baz and so if I were to do pattern matching I'd actually have to do the whole nine yards for each one of them. You can also cheat and do this which I think probably isn't the best practice because if you add a new value or a new type to your Enum this won't let you know that you haven't covered it in all the other cases.
[00:06:53]
And so, it can be dangerous to use that. But nonetheless, this is super cool or at least I think pattern matching is like that's pretty magical, and it can even keep on going pretty deep, you can keep on matching further and further. So if I had say Foo 2 that is an option, which is another option's just another Enum.
[00:07:15]
It's a generic Enum, meaning that you provide, it's the type you want it to be. And that's the type it is. I can now jump in here and go Foo2, and then I can even grab out the options some type. And then grab the value from that so now I'm handling the specific case of my Enum that is a Foo2 that has the inside type that is a specific value of some, right?
[00:07:40]
Which me means I can also handle the other case of none, which is the other value of a option. So options we'll go over options in just one second but as you can see I can keep on pattern matching deeper and deeper so if your types are super huge You can pattern match unlimitedly, right?
[00:07:56]
And this thing will let you know, what cases you've missed. So one more thing, and then I'll answer that question. If you look right here, it's letting me know that I'm missing some things that need to be covered. Which I think it's pretty radical, that it can tell these things.
[00:08:09]
So, all right, Question?
>> Can you Enum functions?
>> I think I wonder if he can I've never tried that let's let's just try a Well, it kind of seems like it will kind of looks like he can. So I've never tried throwing in one of these but let's see, a bar and I'm gonna return an i32 return five, that's an ampersand sign, and three up and let's just pass in bar.
[00:08:43]
What is value? Is a function and hey, look at that it works. That's kind of a fun idea. Never thought about joining that up. Also, one thing I really do like is that the function syntax, matches function syntax, TypeScript, it's like, you can create a function. But if you want to say it as what it's just like slightly off.
[00:09:01]
And it's kinda bothersome. For those that don't know what I'm saying, is that if you wanted to create a type it would be this and then this is the return value, right? That it's not that's not quite how you specify a function. That's how you inline a function.
[00:09:14]
So it's like a little bit of a I'm sorry it's just such a pedantic point, I'm sure nobody actually cares, I care deeply though so there you go so yes so you can these are pretty advanced types, right? So this thing could be something that could return another RSEnum, the mind is being blown right here right?
[00:09:32]
So you can create some fun stuff. So why don't I show you Enums right, a, pretty cool right but, b, there's more to it. There's actually a very specific reason so here skip through all this we've already talked about that, so we can also do generics on him right?
[00:09:48]
So I can say Enum foo, has the generic type t, and it's only member bar has a subtype t, right? Anyway, so you can see. And that means you can also have multiple values, right? I could have t and v and have two different subtypes with those, each one so that way on the outside I can specify what types I want, than the Enums just naturally work that way.
[00:10:09]
Fantastic, right? So how's this practically useful? Well, it lists with many types we already talked about that heterogeneous list and Enums beautiful, right? But more so nullable and error handling. So let me show you what I mean by Nullable. So I'm just gonna program this up really quickly I always like programming things more than I do like that, I just like programming them more than just simply showing them on a whiteboard so if I do it like this type Foo and it has some type bar and this thing is potensly string, right?
[00:10:41]
It might be a string so what actually is bar? If I had a function called do something and inside of do something I take a foo, right? And let's just say I return a boolean. Don't get your languages mixed up. I could do something like if foo.bar. Do something right here, right?
[00:11:02]
We'll just return true. Yeah, don't ever do this kind of programming. You should just not do that. Else, you could have other things in here, right? And then return false right? So there you go, we have this beautiful, nice thing that does one thing on one side. And the reason why that is is because bar actually has two types, right?
[00:11:19]
It has the type of undefined, and it has the type of string. So you get two for the price of one. Now, most people feel like this is really great. I actually think this is kind of crappy. And there's good reasons why I think this is kind of crappy.
[00:11:34]
It's just that you always find yourself doing all these checks, and it can be a bit painful. And the reality is life is a little bit worse than your types and so sometimes your types are actually undefined, then you have to go back and find out what the heck happened because people don't keep up the contracts bla bla bla bla It can be a little bit rough.
[00:11:51]
Rust takes a different kind of approach to this so I kind of alluded to it right here it's called an option type, and to make sure that I'm actually on board with this let's go right here, so here we go this is what is referred to as the Nullable in rust, it is an Enum called an option, it has a generic parameter t and it has the none and it has a sum.
[00:12:12]
And the sum obviously has the generic type, as its type that it has underneath. So it's the exact same thing as that question mark operator effectively either there's nothing there or there's something there. But it's a little bit more fun than that, so let's let's actually do that really quickly so I'm gonna just take this away take that away and let's go like this let foo equals some five.
[00:12:35]
So just like Enums, we can do this, so one nice thing about options is that it actually in lines the types right here, so notice that I don't have to say option colon colon some, I can just say some because it's such a used Enum there just gonna make a kind of like a first class citizen.
[00:12:54]
So you just have this nice little reference right here, so I have some. All right that means I can do this exact same if let some, so I go if let some you know value equals foo and what do I get out of here? I get out and i32 exact same thing.
[00:13:09]
I can pattern match my way through via either the match or an if statement so I can do some value here and do stuff here or the nun case and do it right here. So it's a bit more explicit it kind of makes you always program those things in but there's more.
[00:13:25]
There's actually what I consider more awesome ways to handle options, is that I can also like this, foo.map, right? And in here, let's just have our variable x. By the way this is a closure. This is equivalent to, so a foo.map if we can do this in TypeScript, these two statements would be equivalent right?
[00:13:46]
One just uses two bars and no fat arrow, pretty much the same thing right? And so as you can see I can actually do something only when there's a value which also makes it really awesome which we'll see here shortly using these things with iterators because we can use a flat map.
[00:14:04]
Flat maps are just they're beautiful constructs we'll see here in a moment but this is pretty dang cool, right? So now you can actually use these dot maps, and for the first three months of using rust, I never used the dot map on options. But it's actually quite fantastic once you start using it what you can do with options in the dot map, it also has a filter.
[00:14:24]
So if it is a value, you only want some of those values, right? So you can imagine a situation where you have a Nullable type. And you only wants some set of values less than 10. I can put in here as long as x is less than 10 as my beautiful little item here, my goodness.
[00:14:46]
If you look at this, whenever you do filters, it's always a reference. So you can do one of two things. You can do a little dereference here. You can make this into a reference or you can pattern match away the reference and now it's an i32. Don't worry about, those are just all the things you have to learn, right?
[00:15:02]
It's very obvious once you look at this error, found it has a unknown type cuz we haven't given it a concrete type yet, found in i32 can't obviously you cannot compare a reference to a non reference that makes sense. You have to compare them at the same level.
[00:15:18]
So there we go. We've compared them at the same level. We'll look at that. As you can see, we can now filter out this value. So if I had a foo, that will say value 11 and I did a dot filter on it, and I returned it, it would return a nun, so it actually keeps the same outer type.
[00:15:34]
And we can keep passing this thing around. But the inner type, the value would get removed because we we don't want to deal with that case. And so these are like super cool constructs. And at first this probably feels a touch overwhelming, but it's a pretty cool construct and I'm going over these things just so you have this kind of in your mind?
[00:15:53]
So I kind of went around all these things that I forget any of them. Yeah, there's also like unwrap, so unwrapped just forces you to get the value out. But if there's no underlying value, your program panics and terminates. So unwraps kind of dangerous. There's unwrap, or where you can pass in the value, the default value if you want it.
[00:16:09]
There's unwrap or else, which sounds ominous, but all it is, is that like say you have a value that you wanna create that costs a lot, right? Say you have a buffer that contains a megabyte worth of data, or you're gonna return a empty megabyte worth of data.
[00:16:23]
Obviously you wouldn't want to keep on creating that megabyte worth of data over and over again, you'd only want that to execute when there's nothing available. And so that's why this obviously creates it versus this will create it lazily. Cheap to create closures, expensive to create the underlying type.
[00:16:38]
You can also map them, we saw that. So you can even see here I'm adding five to it, pretty fantastic
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops