first, also hey, let me know what you think about this code video? I tried to make LOTs of code, but cool and exciting. (also like the video, ty ty :))
Might be my favorite one yet! I really like how you "show, don't tell" us that Rust is better. Currently halfway through the Rust Handbook, hoping I get an idea for something to create soon!
hope you keep doing stuff like these. I know you are taking on a different arch doing click baits, but you are truly a good teacher dont turn to the dark side :D
You should start now, cuz learning Rust takes a WHILE 🤭 ( *while = between 1 and 25 yrs depending on ur current knowledge level and time u put into it 😅)
Oh my God, these animations and the code presentations are God tier! What the fuck is this super high quality!!! Also the explanations are top notch. The video is amazing! 10/10
Seems very similar to language features from the FP world, specifically OCaml. The match functionality with extracting out data from container values is so powerful that it serves as the basis for most algorithms in OCaml. It’s pretty cool to see so many languages adopting FP language features like Python and Rust taking matching.
Funny you should say it. Rust did get a lot of inspiration from other languages such as OCaml and Swift, etc. In fact, the Rust compiler was written in OCaml before being self-hosted.
I am currently doing my CS undergrad and we are doing a one-year-long team-programming exercise. We have to do this in Java and in our code we basically have multiple enums that are templates to build functions out of. The hoops you have to jump through to make this a reality in Java are insane (we ended up coding a bunch of Factories) and I am quite jealous that it does not work like in Rust.
Waiting for more Rust jobs, to finally switch from TypeScript to Rust. I love TypeScript sooo much, I written lots and lots of code during 5 years of my career, but Rust seems to me to be my next step
It's just a trend. It's very annoying to work with (which is ironic) and it takes 10 years to compile a hello world app. Even if it gets more popular, the whole world will not adopt it if the don't fix at least these problems. So it will stuck at a point. Typescript is the best for its usecase. Rust is not the best in ANYTHING.
Switch from TypeScript to Rust? There programming languages are geared towards fundamentally different niches, they are not interchangeable. You won't be writing anything client-side for a Website (e.g. for a Browser) in Rust - because browsers don't run Rust code.
@@itsimplified Not really. Browsers also run WebAssembly which Rust can be compiled to. So you can use Rust framework like Leptos to build Web Apps. Also TS is used for writing Node server-side applications which you can also do in Rust. So... they are almost interchangeable 😅
@kamilksen I saw from WebAssembly's official doc the other day saying they're still catching up for resource-intensive stuff like video editing/image/computer vision rendering stuff because for now, Rust doesn't support those as neatly as Javascript does. I'm sure soon enough, especially with more traffic/usage, they'll be caught up. Nothing starts out popular. It's adoption and iteration for improvements that make anything we have today "popular". "How many browsers are made of WebAssembly" is a regressive way of looking at tech :), and quite frankly, might become irrelevant the more popular it gets.
@@mannycalavera121 yeah, rust's functional power inherited from haskell allows for ultimate concise solutions. You can be as much semantic as the language is able to on both OOP or functional programming. Rust is the human being game changer
Also pretty cool is that Option (which would be the same as a nullable pointer) actually is represented as a single nullable pointer in memory, since rust knows that the pointer (Box) cannot be null, and therefore uses null to represent None.
This feels pretty similar to Java enums. What I like about Rust's approach is having errors propagate as values, since like you said, you know exactly what you're getting just from the return type including potential errors
@@mskiptr Hmm I don’t think you can quite do something like that. Java enums basically are just a set of pre-defined instances of the class, so you can’t have individual enum values have different sets of properties (but, they can have the same set of properties). I suppose Rust enums are more akin to tagged unions whereas Java enums are more or less just a set of predefined instances.
@@mskiptr that would be sealed interface TreeOfInts { record Node(TreeOfInts left, int value, TreeOfInts right) implements TreeOfInts {} record Nil() implements TreeOfInts {} }
The result types feel similar to Java checked exceptions. Interesting, in general I think the industry moved over to unchecked exceptions due to the caller not being able to handle properly all the possible exceptions. Seems like in Rust this works better I suppose? Also was glad to see that Kotlin enums share some similar traits as Rust which is neat. Great job with the code highlighting Prime! Did use any programs to achieve this darken / focus effect on the code?
Checked exceptions are less flexible, unchecked exceptions are error-prone. I really like Rust’s method because it’s flexible and prevents unhandled errors.
The point of Rust type system (enums included) is that it guarantees that there is no undefined behavior in your code. It's not like here we have type system, here we have exception system and they somehow working together if programmer knows what he is doing. No, that's the old way and practice tells that it never works. Instead in Rust type system IS exception handling system. Why? Because types is the only thing that always guaranteed in compilation time. So that what makes this effect "if it compiles -- it works"
Hey Prime, nice video. Have you ever tried Haskell? I would be curious what you thought of it. Rust has so much momentum now and I wish some other really cool languages like Zig, Haskell, or even Common Lisp or Clojure could get some love from a big voice.
Nice video! On the array example, am I right that this is demonstrating the difference between structural and nominal typing, and how the latter is stricter?
ThePrimeagen, I am learning rusting to create a cross platform app. I'm thinking of using rust for the backend. For the front end, should I rely on a Javascript framework or a rust framework like Dioxus?
a fun, random fact about rust enums: if you want to have an "any" type (i.e. retrieving a value from a database store), you can use it in order to map db types to rust types. this is how surrealdb handles query values internally for each column
Rust is just such a well-designed language in general, and enums are a great example. Rust's enums are a combination of the classic enum concept of associating a constant int with a defined string to constrain values to a range of valid values, mixed with the idea of a union type, where you can have one variable that can hold multiple types of data. Most mainstream languages have seriously sucked at handling union types properly. Typescript somehow manages to even screw up the constant to act as a value constraint part too.
You can use typescript enums to enforce that each case is matched. It's not on by default which would be nice, but you can get it to give you a type error by sending the variable you're switching over to never. function getColorName(c: Color): string { switch (c) { case Color.Red: return "red"; case Color.Green: return "green"; // Forgot about Blue default: const exhaustiveCheck: never = c; throw new Error(`Unhandled color case: ${exhaustiveCheck}`); } }
FWIW, you can get exhaustiveness checking in TS switch statements by using something like default: notReachable(value); where function notReachable(value: NoReturn): NoReturn {} Anyway, algebraic data types FTW. Glad languages like Rust are looking at functional languages for inspiration.
For 0:36, I cover this issue with the `@typescript-eslint/switch-exhaustiveness-check` rule in eslint. It would be ideal if it was a TypeScript warning or option, but I think most TypeScript devs use eslint anyway so I don't think it's a big issue
Looking at this, coming from Swift to Rust might actually be way easier than I thought. This sounds exactly like Swift enums, even Optional is basically enum { case none, some(T) }
Yep. Option/Optional and Result are the same in both languages. Swift just has some extra syntactic sugar around Optionals, with being able to declare properties like `let thing: Int?` whereas I think you have to use the more verbose Option syntax in Rust. Also, Swift allows implicit optional promotion, where you can pass a non-Optional value to a property expecting an Optional without manually wrapping in a Some case.
Don't forget let else, which landed recently. It's the early return guard version of if let, although it lets (heh) you do other things as well. And it moves so much code to the left.
Rusting iron blazingly fast is fire. Doing it even more blazingly fast would an explosion. Rust is ashes from love of iron and oxygen slowly burning till they are both consumed. Ah, the romance.
Switch and enums in TypeScript won't have exhaustive checking like match and enums in Rust. However, using enums with records will. For example ``` enum Color { Yellow = 'Yellow', Red = 'Red', Green = 'Green', Blue = 'Blue', } type CanPrint = { print: () => void } type ColorRecord = Record const printColor = (color: Color) => { const colors: ColorRecord = { [Color.Red]: { print: () => console.log('red') }, [Color.Green]: { print: () => console.log('green') }, [Color.Blue]: { print: () => console.log('blue') }, } colors[color].print() } ``` Here Typescript will do an exhaustive check of the enum variants. Since Color has a `Yellow` variant in the enum `const colors` will give you a typescript error like: ``` Property 'Yellow' is missing in type '{ Red: { print: () => void; }; Green: { print: () => void; }; Blue: { print: () => void; }; }' but required in type 'ColorRecord'. ``` Still nothing as great as Rust, but nothing usually is.
I watched this because you mentioned being disappointed in the performance of the video somewhere else. While there's a audience for it, I think it hits this weird duality of "I already know what this is" and "I can't even guess what this is." Probably the best hook is going to be "I know a little and want to know more." Just my two cents. For me this is all just haskell but verbose (not that I'm in love with Haskell). Sum types and verifying correctness of the program and pattern matching... it's neat but it can be such a pain to refactor or rearrange. At least in Rust you print a message without having to pollute your whole program with Effect monads XD I'm still on the fence about types, I like them in C where they have real meaning about the memory you're working with, but I never feel rescued by them. They can never be perfect and there's this whole spectrum of how painful you want them to be versus how effectively they will reveal bugs and the balance just never hits the right mark for me. I'm very Rich Hickey on it, I want to be able to amend my software easily without changing existing behaviour, I don't want types to guide me through making breaking changes that are going to leave behind bugs regardless. I just hate brittle software that needs a million changes when no functionality actually broke. Don't know if any of that makes sense, but cheers anyway I love your videos
I really wish the tech-fluencers take inspiration from this much effort into putting such a valuable lesson for us. I would really wish that you publish writings using GPT if you find it helpful for speed for publication. I would love to read code-oriented and example-oriented style in blogs. It really makes it easier for me to "fork" the examples and consume it in my own notes, while allowing you to funnel to potentially a wider audience. No, this comment is not GPT-generated, and I nor did I tell it to explicitly write like I'm 13 years old
1:07 If you want this in TypeScript: function never(n: never) { return n } Then in the switch(x) you add: default: never(x); If all enum cases are accounted for, TS will narrow x to never and will compile this. If x is anything other than never (even any!), it will refuse to compile until you add the case. If a return is needed, you can just return the never(x), or return a sentinel value, or throw whatever. Returning a never type is always valid, and the enum safety is still there due to the invalid never(x) call. It's as safe as you can make this in TypeScript and will only fail during runtime if your type narrowing above is completely busted due to bad typeguards, in which case you have bigger problems on your hand, and you'd have runtime issues either way. In any case, it's better than not using it whenever you want to ensure all enum cases are accounted for.
Dang! I didn't know enums could have methods in Rust. That's pretty cool. As a casual Rust dev, I find it hard to discover some of the rare pearls of Rust like this one. You just have to know that this feature exists. I have never heard of methods on enum in any other languages, making hard to look for this. Even if I already knew 95% of what you talked about in your video, the enum part blew my mind. Thanks Prime for doing these kind of videos. I really like the content you create. Keep it up!
I think you should mention exhaustive switches in typescript via function assertUnreachable(x: never): never { }. It would also make a lot of sense to mention tagged union types in typescript which brings it closer to rust enums.
Pretty neat explanation about how Rust Enums are superior to Typescript Enums and also its type system in general. I wouldn't say it's Typescript's fault as it tries to solve an issue to a language that wasn't made with Types in mind. And second, about the presentation style, animations, etc, gorgeously and simple, not bloated with crazy animations; highlighting side by side TS and equivalent in Rust was really nice. 10 out of 10 for this presentation and explanation
A fix to the scalability issue you mention with traditional enums is to make an X macro that expands into a static array. This way, it is impossible to miss a single enum type. Then, you don't need a function, rather index into the static array using the enum name to yield its value.
The rust enums often remind me of Kotlin sealed classes, I know their are not fundamentally the same thing, but the experience in using them is somewhat similar. You should take a look at Kotlin, it's a really powerful language and great for backend dev (expecially with ktor ;)
Thanks for highlightning interesting parts. Rust looks really promising. Regarding exceptions, if I get you right, there is interesting opinion on forcing explicitly manage exeptions. Article is The Trouble with Checked Exceptions
Swift enums are exactly the same, both in terms of how the compiler complains if you pattern match against an enum value but don’t explicitly handle every case, and in being able to attach associated values to them. Super powerful technique.
> Who handles the error? This is why I fundamentally abhor exceptions for error handling. Every time I try to catch exceptions without resorting to `catch (BaseException e)`, assuming the language has one base class for exceptions, I always find one undocumented and uncaught exception that crashes my app, because the only way to find all the exceptions thrown is to read all the functions you call, and all the functions those functions call, and all the functions those functions call, ad nauseam.
I'd say the "string | number | Custom" type isn't quite equivalent to the Rust's enum, because there are no primitive variants in the Rust example (since that is not possible, which why we need to wrap the value type). You can think of each variant as its own type that can wrap around their associated values. It would be more correct to say type Item = Foo | Bar | Baz; Where any variant Foo, Bar and Baz are typed as: type Foo = { kind: "Foo"; // Discriminator value: string; // Bar = number, Baz = Custom } This way we also avoid the issue with pushing strings to the array. You could think of this as being similar to the more verbose version in Rust: enum Item { Foo { value: String }, Bar {.value: usize }, Baz ( value: Custom } } Albeit with extra step of defining the discriminator manually.
Thank you for providing this comparison of Rust and JavaScript! Your perspective has inspired me to create my own videos on the topic. Thanks, see you soon! 💪
Would LOVE a video on how you manage to work full time, run a twitch and yt channel, and learn and work on your skills. All while having 4 kids and a wife!? I struggle harddddd to find more than 2-3 free hours per week and i’m a senior dev with a wife and 2 kids. Would love to know how you organize your time and make it all happen!
Apart from checking a new field while matching an enum, I think Java is just about similar to Rust in these regards. Of course, the performance difference is huge, but still, I still don't feel like its worth migration away from Java (just based on this feature). I'll explore other functionalities and the checks that rust compiler runs while making a binary, since that looks really cool, ngl.
the second point you brought up about Item and string seems to be based on the duck-typed nature of TS. TS must be duck-typed because the types don't exist at runtime, so you can only assure that types are compatible with each other, but not actually the correct instances (unless you use prototypes/classes). so i think this applies to every statically typed language, not just TS. maybe not a fair comparison?
These comparisons are a really good way to convince people to learn rust. I am a Frontend dude, I use Typescript, I hate it but I use it because it's better than plain JS but I still hate it.
My favorite part about result is that you can make your own error type that you can implement Into for - meaning you can seamlessly turn a random imported error type into your own with minimal code and clutter (usually *less* clutter)
Rust is brilliant. This error handling however does put a lot of boilerplate match/if statements. But I agree its better than debugging random crashing & failures.
Swift also has all these features with enumerated & you’d be surprised how much easier everything is to maintain when using enums this way. The possible permutations are logically sealed & so it’s very hard to miss things if you base your foundation of workable items in enums. The best kind of code is the kind that won’t compile if you do something the system isn’t meant to do.
Enums in rust sound a lot like structs, a type that hold some data and you can define methods on those types. Is there some fundamental difference between structs, in Go for example, and enums in rust?
a more semantically equivalent version of the Item type from typescript would technically be a ``` union Item { foo: String, bar: usize, baz: Custom } ``` though it is more semantically equivalent because it has a lot of the same issues as the typescript version, as well as being much more unsafe to actually use.
You should have mentioned the feature of forcing non exhaustive pattern matching on an enum. It is done in libraries where you want to have the option of adding more variants without breaking users' code. #[non_exhaustive] enum MyEnum{...}
It's also worth mentioning (i don't know about TS), that rust enums are ADT-sums and you can have aribatary data inside variants, in most languages like c++ enum is int with name
my only nitpick about rust enums is if you want to use c like enums for example enum Foo { red, blue, green } it is really annoying to cast the enum to an integer that'd be 0,1,2 or back and forth (from integer to the enum), which can be a little annoying, now there are crates to do it more seamlessly but still, it was a little anoying at times when writting a binary protocol.
Well yes, I get that, but something like that is also achievable in Typescript. It's not as clean and creates an object, but it gives type hints. But having it checked for real at compile time and not just sort of at transpile time is an advantage. type Custom = { name: string; age: number; } const Enum = { Foo: "foo", Bar: "bar", Baz: "baz", } as const; type Enum = typeof Enum[keyof typeof Enum]; type Item = { [Enum.Foo]: string; } | { [Enum.Bar]: number; } | { [Enum.Baz]: Custom; } const foo: Item = { [Enum.Foo]: 'i am a string' } if (Enum.Foo in foo) { console.log(foo.foo); } function append(arr: Item[]) { arr.push({ [Enum.Bar]: 69 }); } const arr: string[] = ["hello", "world"]; append(arr); // Argument of type 'string[]' is not assignable to parameter of type 'Item[]'. Type 'string' is not assignable to type 'Item'. ts(2345)
love how you showed the code, i think if you took more breaks to clarify everything it would be even better, (like okay this is what we did up to this point) lovin it tho
I love how must really old news can make so much excitement😂 The "enum type" in rust is equivalent to the disjoint union type in F#, haskell, and ocaml which all inherit it from ML (Meta language not machine learning) defined and implemented in 1970.. so not a new thing at all.. the Standard ML (implementation) was already in 1970 comparable in speed to C, even though it used exotic things like a GC.. this should be taken with a grain of salt.. btw if you are unsure ML pre date haskell, and haskell is defined to be in the "ML family"
Awesome Prime, bring more differences and why Rust is better!!! First look enums seems the same in TS and Rust, but know I now there's a huge difference!!
That comparison isn't accurate. In the switch example, you usually add a default case which contains an assertNever, so you catch that error. Or if your returning in every brach of the enum cases, definite returning checks will result in the same safety. Regarding the union example: the behavior is due to JS. If you want to be more safe, most people use tagged unions (discriminated unions), which are the actual equivalent to Rusts enums (I think rust even does the same internally). Some people also define their own result monad, like the Result in rust, based on tagged unions. In TS, you usually don't need the Optional monad, since you can just use T|null. Yeah, enums in rust are cool. Way cooler than something like std::variant. But TS can be cool, too. Sometimes even cooler, with the control-flow-based type narrowing, which is something that rust sadly doesn't have.
Those enums are pretty close to java and java has an Optional as well as primitive pattern matching. Looks like rust would be pretty reasonable to learn.
You can make ts enum switch case to also throw an error if not all cases are handled by using never in default. Even despite this fact rust enums is still much better since you don't need to remember to always include default, and not just that. enum Color { Red, } function test(x: Color) { switch (x) { case Color.Red: return; default: const test: never = x; } }
@@ThePrimeagen indeed, Rust' type system is very similar to Haskell 2010 (but the later has higher kinded polymorphism). Both languages took Algrebraic Data Types (tagged enums with pattern matching) from Standard ML and OCaml. Haskell included type classes and typed families, named Traits and associated types in Rust if I am not mistaking. That being said, both languages are very different at the term level. And Haskell is GC'd... Also Haskell has more monads hahaha
first, also hey, let me know what you think about this code video? I tried to make LOTs of code, but cool and exciting. (also like the video, ty ty :))
hey prime, where do I find the streams where you teached BigO and data structures? I cant find it ;-;
Might be my favorite one yet! I really like how you "show, don't tell" us that Rust is better. Currently halfway through the Rust Handbook, hoping I get an idea for something to create soon!
hope you keep doing stuff like these. I know you are taking on a different arch doing click baits, but you are truly a good teacher dont turn to the dark side :D
I really love this new style with showing the ctode, great video!
I feel so hyped to learn Rust every time you make a video on it
yayaya! i feel like this is great
Are you a c/c++ dev?
@@pedrolucasdeoliveiralara8199 I'm a TS dev
@@matheusnogueira7219 then you should probably learn c/c++ before learning rust.
You should start now, cuz learning Rust takes a WHILE 🤭 ( *while = between 1 and 25 yrs depending on ur current knowledge level and time u put into it 😅)
Oh my God, these animations and the code presentations are God tier! What the fuck is this super high quality!!! Also the explanations are top notch. The video is amazing! 10/10
Gotta love Motion Canvas
@@NathanHedglin thank you, i was looking for this :)
I love clear Result/optional types, these are soo much better then exceptions!
Seems very similar to language features from the FP world, specifically OCaml.
The match functionality with extracting out data from container values is so powerful that it serves as the basis for most algorithms in OCaml.
It’s pretty cool to see so many languages adopting FP language features like Python and Rust taking matching.
Funny you should say it. Rust did get a lot of inspiration from other languages such as OCaml and Swift, etc. In fact, the Rust compiler was written in OCaml before being self-hosted.
Wish more languages preferred total functions over partial functions that throw exceptions, checked exceptions are decent, but I prefer the latter.
ReScript is the OCaml for JS, and thus has a better type system than TS, comparable to Rust.
Prime, I loved this style of comparing code. Really, really helps and also really dig that colour scheme;)
enum RealProgrammingLanguages { Rust, Haskell }
I know this concept from Haskell and Swift. They‘re great! I really hope, that there will someday be an equivalent in TS
I am currently doing my CS undergrad and we are doing a one-year-long team-programming exercise. We have to do this in Java and in our code we basically have multiple enums that are templates to build functions out of. The hoops you have to jump through to make this a reality in Java are insane (we ended up coding a bunch of Factories) and I am quite jealous that it does not work like in Rust.
Woah Prime! Calm down there! If you continue like this I'll end up learning rust
you just tweeted me this :)
@@ThePrimeagen caught in 4K
Waiting for more Rust jobs, to finally switch from TypeScript to Rust. I love TypeScript sooo much, I written lots and lots of code during 5 years of my career, but Rust seems to me to be my next step
It's just a trend. It's very annoying to work with (which is ironic) and it takes 10 years to compile a hello world app. Even if it gets more popular, the whole world will not adopt it if the don't fix at least these problems. So it will stuck at a point. Typescript is the best for its usecase. Rust is not the best in ANYTHING.
Switch from TypeScript to Rust? There programming languages are geared towards fundamentally different niches, they are not interchangeable. You won't be writing anything client-side for a Website (e.g. for a Browser) in Rust - because browsers don't run Rust code.
@@itsimplified Not really. Browsers also run WebAssembly which Rust can be compiled to. So you can use Rust framework like Leptos to build Web Apps. Also TS is used for writing Node server-side applications which you can also do in Rust.
So... they are almost interchangeable 😅
@@DEVDerr How many websites made in WebAssembly have you seen? Which percentage of the web are these?
@kamilksen I saw from WebAssembly's official doc the other day saying they're still catching up for resource-intensive stuff like video editing/image/computer vision rendering stuff because for now, Rust doesn't support those as neatly as Javascript does. I'm sure soon enough, especially with more traffic/usage, they'll be caught up. Nothing starts out popular. It's adoption and iteration for improvements that make anything we have today "popular". "How many browsers are made of WebAssembly" is a regressive way of looking at tech :), and quite frankly, might become irrelevant the more popular it gets.
It's really crazy how readable rust can be if you don't try to get too fancy. Loving getting to work with TS and Rust on my 2 projects right now
such luck!
When I write my potato rust I find it very readable. When I start using other peoples clean optimised Rust it's alien language.
@@mannycalavera121 yeah, rust's functional power inherited from haskell allows for ultimate concise solutions. You can be as much semantic as the language is able to on both OOP or functional programming. Rust is the human being game changer
Yep, Rust's arcane parts are wwaaaay more readable compared to C++ templates.
@@CasimiroBukayoto old C++ templates, the modern ones are so much readable ... even more than rust (rust macros are hard to read).
While this video may not be the best performing video, the knowledge packed into it is stellar. Thanks for making it Prime.
:)
This type of format is so good. I feel that re-watching the video does not tire me at all if I don´t get the concept in the first run.
Also pretty cool is that Option (which would be the same as a nullable pointer) actually is represented as a single nullable pointer in memory, since rust knows that the pointer (Box) cannot be null, and therefore uses null to represent None.
What software you used to show the code? Is the same as code aesthetics? Just curious. I really liked it.
This feels pretty similar to Java enums. What I like about Rust's approach is having errors propagate as values, since like you said, you know exactly what you're getting just from the return type including potential errors
Can the Java enums have a value attached to one of the variants? I thought they are just ints underneath, but if they do that's a gamechanger
@@mskiptr Yeah they can. Each of the items of the enum is an instance of the object you define
@@chatt7486 So how would you write the following in Java?
enum TreeOfInts {
Node(TreeOfInts, u32, TreeOfInts),
Nil,
}
@@mskiptr Hmm I don’t think you can quite do something like that. Java enums basically are just a set of pre-defined instances of the class, so you can’t have individual enum values have different sets of properties (but, they can have the same set of properties). I suppose Rust enums are more akin to tagged unions whereas Java enums are more or less just a set of predefined instances.
@@mskiptr that would be
sealed interface TreeOfInts {
record Node(TreeOfInts left, int value, TreeOfInts right) implements TreeOfInts {}
record Nil() implements TreeOfInts {}
}
I remember learning how Rust enums can hold a subtype and it blew my mind.
Did you use some software to edit the code slides, or was this done by your editor?
The result types feel similar to Java checked exceptions. Interesting, in general I think the industry moved over to unchecked exceptions due to the caller not being able to handle properly all the possible exceptions. Seems like in Rust this works better I suppose?
Also was glad to see that Kotlin enums share some similar traits as Rust which is neat.
Great job with the code highlighting Prime! Did use any programs to achieve this darken / focus effect on the code?
Checked exceptions are less flexible, unchecked exceptions are error-prone. I really like Rust’s method because it’s flexible and prevents unhandled errors.
Yeah, I am glad that more languages are adopting functional programming feature. That with OOP, we can have the better of both worlds
The point of Rust type system (enums included) is that it guarantees that there is no undefined behavior in your code. It's not like here we have type system, here we have exception system and they somehow working together if programmer knows what he is doing. No, that's the old way and practice tells that it never works. Instead in Rust type system IS exception handling system. Why? Because types is the only thing that always guaranteed in compilation time. So that what makes this effect "if it compiles -- it works"
Hey Prime, nice video. Have you ever tried Haskell? I would be curious what you thought of it. Rust has so much momentum now and I wish some other really cool languages like Zig, Haskell, or even Common Lisp or Clojure could get some love from a big voice.
Gawd knew Clojure and Haskell wud be too powerful if He made the popular 😭
I like to think of Rust enums as C unions. I know it's not a one-to-one comparison but I think it makes the most sense
i think its best to do that :)
Nice video! On the array example, am I right that this is demonstrating the difference between structural and nominal typing, and how the latter is stricter?
ThePrimeagen, I am learning rusting to create a cross platform app. I'm thinking of using rust for the backend. For the front end, should I rely on a Javascript framework or a rust framework like Dioxus?
a fun, random fact about rust enums: if you want to have an "any" type (i.e. retrieving a value from a database store), you can use it in order to map db types to rust types. this is how surrealdb handles query values internally for each column
Prime, is this video part of an upcoming Rust For TypeScript Devs course. Amazing explanations, as always. Thank you.
Rust is just such a well-designed language in general, and enums are a great example. Rust's enums are a combination of the classic enum concept of associating a constant int with a defined string to constrain values to a range of valid values, mixed with the idea of a union type, where you can have one variable that can hold multiple types of data. Most mainstream languages have seriously sucked at handling union types properly. Typescript somehow manages to even screw up the constant to act as a value constraint part too.
Hey Prime! loved the vid. One quick question, what software do you use to edit your coding videos like this?
You can use typescript enums to enforce that each case is matched. It's not on by default which would be nice, but you can get it to give you a type error by sending the variable you're switching over to never.
function getColorName(c: Color): string {
switch (c) {
case Color.Red:
return "red";
case Color.Green:
return "green";
// Forgot about Blue
default:
const exhaustiveCheck: never = c;
throw new Error(`Unhandled color case: ${exhaustiveCheck}`);
}
}
FWIW, you can get exhaustiveness checking in TS switch statements by using something like
default: notReachable(value);
where
function notReachable(value: NoReturn): NoReturn {}
Anyway, algebraic data types FTW. Glad languages like Rust are looking at functional languages for inspiration.
For 0:36, I cover this issue with the `@typescript-eslint/switch-exhaustiveness-check` rule in eslint. It would be ideal if it was a TypeScript warning or option, but I think most TypeScript devs use eslint anyway so I don't think it's a big issue
Looking at this, coming from Swift to Rust might actually be way easier than I thought. This sounds exactly like Swift enums, even Optional is basically enum { case none, some(T) }
Yep. Option/Optional and Result are the same in both languages.
Swift just has some extra syntactic sugar around Optionals, with being able to declare properties like `let thing: Int?` whereas I think you have to use the more verbose Option syntax in Rust. Also, Swift allows implicit optional promotion, where you can pass a non-Optional value to a property expecting an Optional without manually wrapping in a Some case.
Don't forget let else, which landed recently. It's the early return guard version of if let, although it lets (heh) you do other things as well. And it moves so much code to the left.
Rust is 👑. Rust is life. Oxide everything. Blazingly rusty. 🦀
Rusting iron blazingly fast is fire. Doing it even more blazingly fast would an explosion. Rust is ashes from love of iron and oxygen slowly burning till they are both consumed. Ah, the romance.
Pattern matching in Elixir is even more mind blowing.
Even better in Haskell
Switch and enums in TypeScript won't have exhaustive checking like match and enums in Rust. However, using enums with records will. For example
```
enum Color {
Yellow = 'Yellow',
Red = 'Red',
Green = 'Green',
Blue = 'Blue',
}
type CanPrint = { print: () => void }
type ColorRecord = Record
const printColor = (color: Color) => {
const colors: ColorRecord = {
[Color.Red]: { print: () => console.log('red') },
[Color.Green]: { print: () => console.log('green') },
[Color.Blue]: { print: () => console.log('blue') },
}
colors[color].print()
}
```
Here Typescript will do an exhaustive check of the enum variants.
Since Color has a `Yellow` variant in the enum `const colors` will give you a typescript error like:
```
Property 'Yellow' is missing in type '{ Red: { print: () => void; }; Green: { print: () => void; }; Blue: { print: () => void; }; }' but required in type 'ColorRecord'.
```
Still nothing as great as Rust, but nothing usually is.
I watched this because you mentioned being disappointed in the performance of the video somewhere else.
While there's a audience for it, I think it hits this weird duality of "I already know what this is" and "I can't even guess what this is." Probably the best hook is going to be "I know a little and want to know more." Just my two cents.
For me this is all just haskell but verbose (not that I'm in love with Haskell). Sum types and verifying correctness of the program and pattern matching... it's neat but it can be such a pain to refactor or rearrange. At least in Rust you print a message without having to pollute your whole program with Effect monads XD I'm still on the fence about types, I like them in C where they have real meaning about the memory you're working with, but I never feel rescued by them. They can never be perfect and there's this whole spectrum of how painful you want them to be versus how effectively they will reveal bugs and the balance just never hits the right mark for me. I'm very Rich Hickey on it, I want to be able to amend my software easily without changing existing behaviour, I don't want types to guide me through making breaking changes that are going to leave behind bugs regardless. I just hate brittle software that needs a million changes when no functionality actually broke. Don't know if any of that makes sense, but cheers anyway I love your videos
Good vid. btw, you can add methods to Enums in TypeScript too
I really wish the tech-fluencers take inspiration from this much effort into putting such a valuable lesson for us. I would really wish that you publish writings using GPT if you find it helpful for speed for publication.
I would love to read code-oriented and example-oriented style in blogs. It really makes it easier for me to "fork" the examples and consume it in my own notes, while allowing you to funnel to potentially a wider audience.
No, this comment is not GPT-generated, and I nor did I tell it to explicitly write like I'm 13 years old
I wondered what tool did you use for the code animations? Great video 🙂👍🏻
1:07 If you want this in TypeScript:
function never(n: never) { return n }
Then in the switch(x) you add:
default: never(x);
If all enum cases are accounted for, TS will narrow x to never and will compile this. If x is anything other than never (even any!), it will refuse to compile until you add the case.
If a return is needed, you can just return the never(x), or return a sentinel value, or throw whatever. Returning a never type is always valid, and the enum safety is still there due to the invalid never(x) call.
It's as safe as you can make this in TypeScript and will only fail during runtime if your type narrowing above is completely busted due to bad typeguards, in which case you have bigger problems on your hand, and you'd have runtime issues either way. In any case, it's better than not using it whenever you want to ensure all enum cases are accounted for.
Prime, what about Java or C# do you not like and prefer Rust over?
Dang! I didn't know enums could have methods in Rust. That's pretty cool. As a casual Rust dev, I find it hard to discover some of the rare pearls of Rust like this one. You just have to know that this feature exists. I have never heard of methods on enum in any other languages, making hard to look for this. Even if I already knew 95% of what you talked about in your video, the enum part blew my mind. Thanks Prime for doing these kind of videos. I really like the content you create. Keep it up!
wait till you hear Dart enums can not only have methods, but constant parameters too.
I think you should mention exhaustive switches in typescript via function assertUnreachable(x: never): never { }. It would also make a lot of sense to mention tagged union types in typescript which brings it closer to rust enums.
JS->TS->Rust pipeline let's gooo. Love this kind of content from your channel.
:) ty ty
Pretty neat explanation about how Rust Enums are superior to Typescript Enums and also its type system in general. I wouldn't say it's Typescript's fault as it tries to solve an issue to a language that wasn't made with Types in mind.
And second, about the presentation style, animations, etc, gorgeously and simple, not bloated with crazy animations; highlighting side by side TS and equivalent in Rust was really nice.
10 out of 10 for this presentation and explanation
Great videos man. Would love to see some on meta skills like your process of learning and how to develop deep understanding of these abstract systems
A fix to the scalability issue you mention with traditional enums is to make an X macro that expands into a static array. This way, it is impossible to miss a single enum type. Then, you don't need a function, rather index into the static array using the enum name to yield its value.
The rust enums often remind me of Kotlin sealed classes, I know their are not fundamentally the same thing, but the experience in using them is somewhat similar.
You should take a look at Kotlin, it's a really powerful language and great for backend dev (expecially with ktor ;)
Beautiful video! I’d recommend slowing down a tad bit tho, felt like you were going too fast at times
Thanks for highlightning interesting parts.
Rust looks really promising.
Regarding exceptions, if I get you right, there is interesting opinion on forcing explicitly manage exeptions.
Article is The Trouble with Checked Exceptions
How'd you animate all those fancy text comparisons?
Great video, as usual! The editing on this one however is next level. Well done! Really easy to follow! Good job! Keep up the good work!
That `if let = value { true } else { false }` can even be shortened with the `matches!` macro which does just that: `matches!(value, )`
You would well fit into an aula giving a lecture to a whole class and each student would come out understanding what they have just learned
He has courses, his personality is a lot less explosive but he really motivates you to learn.
Swift enums are exactly the same, both in terms of how the compiler complains if you pattern match against an enum value but don’t explicitly handle every case, and in being able to attach associated values to them. Super powerful technique.
> Who handles the error?
This is why I fundamentally abhor exceptions for error handling. Every time I try to catch exceptions without resorting to `catch (BaseException e)`, assuming the language has one base class for exceptions, I always find one undocumented and uncaught exception that crashes my app, because the only way to find all the exceptions thrown is to read all the functions you call, and all the functions those functions call, and all the functions those functions call, ad nauseam.
I'd say the "string | number | Custom" type isn't quite equivalent to the Rust's enum, because there are no primitive variants in the Rust example (since that is not possible, which why we need to wrap the value type). You can think of each variant as its own type that can wrap around their associated values.
It would be more correct to say
type Item = Foo | Bar | Baz;
Where any variant Foo, Bar and Baz are typed as:
type Foo = {
kind: "Foo"; // Discriminator
value: string; // Bar = number, Baz = Custom
}
This way we also avoid the issue with pushing strings to the array.
You could think of this as being similar to the more verbose version in Rust:
enum Item {
Foo { value: String },
Bar {.value: usize },
Baz ( value: Custom }
}
Albeit with extra step of defining the discriminator manually.
Thank you for providing this comparison of Rust and JavaScript! Your perspective has inspired me to create my own videos on the topic. Thanks, see you soon! 💪
Have you ever tried elm for front end? It's also strict toyed language and I think someone who loves types in Rust must love elm
Would LOVE a video on how you manage to work full time, run a twitch and yt channel, and learn and work on your skills. All while having 4 kids and a wife!?
I struggle harddddd to find more than 2-3 free hours per week and i’m a senior dev with a wife and 2 kids. Would love to know how you organize your time and make it all happen!
hi primagen, do you mind sharing the language you write mostly at netflix?
You and the "No Boilerplate" channel have gotten me so interested in trying Rust
Apart from checking a new field while matching an enum, I think Java is just about similar to Rust in these regards. Of course, the performance difference is huge, but still, I still don't feel like its worth migration away from Java (just based on this feature). I'll explore other functionalities and the checks that rust compiler runs while making a binary, since that looks really cool, ngl.
Most languages are the same as Rust, C# for example is the same. Rust has become a religion almost followers are going crazy.
@@MrNatsuDragneel I feel the same, as I watch on more and more of Prime's videso on Rust.
the second point you brought up about Item and string seems to be based on the duck-typed nature of TS. TS must be duck-typed because the types don't exist at runtime, so you can only assure that types are compatible with each other, but not actually the correct instances (unless you use prototypes/classes). so i think this applies to every statically typed language, not just TS. maybe not a fair comparison?
Thank you very much for the Inspiration and motivation you give me / us trough youre wonderfull blaizinglyyyyyyy fast videos !!! I love you're vibe !
you are welcome
These comparisons are a really good way to convince people to learn rust. I am a Frontend dude, I use Typescript, I hate it but I use it because it's better than plain JS but I still hate it.
4:00 “Every square is a quadrilateral, but not every quadrilateral is a square” 🤓🤓
Sorry had to do it, love ur videos btw keep going ❤
One of my favorite enums is Ordering. So easy to read.
My favorite part about result is that you can make your own error type that you can implement Into for - meaning you can seamlessly turn a random imported error type into your own with minimal code and clutter (usually *less* clutter)
Rust is brilliant. This error handling however does put a lot of boilerplate match/if statements. But I agree its better than debugging random crashing & failures.
legit a great video. I do feel bad that it's doing not doing as well as your other ones. I share your pain in that regard.
What do you use for the code part of the video?
Swift also has all these features with enumerated & you’d be surprised how much easier everything is to maintain when using enums this way. The possible permutations are logically sealed & so it’s very hard to miss things if you base your foundation of workable items in enums.
The best kind of code is the kind that won’t compile if you do something the system isn’t meant to do.
Most languages are the same as Rust, C# for example is the same. Rust has become a religion almost followers are going crazy.
bruh, if you make this a series I might have to learn rust
Enums in rust sound a lot like structs, a type that hold some data and you can define methods on those types. Is there some fundamental difference between structs, in Go for example, and enums in rust?
Holy crap. Just came across your channel. Love the production and content quality. Subbed!
The video was entertaining and educational at the same time, Well Done! 😄
Preach it bro! For a future where we spend more time building and less time debugging!
a more semantically equivalent version of the Item type from typescript would technically be a
```
union Item {
foo: String,
bar: usize,
baz: Custom
}
```
though it is more semantically equivalent because it has a lot of the same issues as the typescript version, as well as being much more unsafe to actually use.
You should have mentioned the feature of forcing non exhaustive pattern matching on an enum.
It is done in libraries where you want to have the option of adding more variants without breaking
users' code.
#[non_exhaustive]
enum MyEnum{...}
It's also worth mentioning (i don't know about TS), that rust enums are ADT-sums and you can have aribatary data inside variants, in most languages like c++ enum is int with name
wow it’s like the marriage of haskell and C
my only nitpick about rust enums is if you want to use c like enums for example enum Foo { red, blue, green } it is really annoying to cast the enum to an integer that'd be 0,1,2 or back and forth (from integer to the enum), which can be a little annoying, now there are crates to do it more seamlessly but still, it was a little anoying at times when writting a binary protocol.
Well yes, I get that, but something like that is also achievable in Typescript. It's not as clean and creates an object, but it gives type hints.
But having it checked for real at compile time and not just sort of at transpile time is an advantage.
type Custom = {
name: string;
age: number;
}
const Enum = {
Foo: "foo",
Bar: "bar",
Baz: "baz",
} as const;
type Enum = typeof Enum[keyof typeof Enum];
type Item = {
[Enum.Foo]: string;
} | {
[Enum.Bar]: number;
} | {
[Enum.Baz]: Custom;
}
const foo: Item = { [Enum.Foo]: 'i am a string' }
if (Enum.Foo in foo) {
console.log(foo.foo);
}
function append(arr: Item[]) {
arr.push({ [Enum.Bar]: 69 });
}
const arr: string[] = ["hello", "world"];
append(arr); // Argument of type 'string[]' is not assignable to parameter of type 'Item[]'. Type 'string' is not assignable to type 'Item'. ts(2345)
Production quality is off the chart! Prime is upping his game!
in the first example switch statement make sense; what if you dont want yellow to do anything? you still have to add it but then immediately break?
love how you showed the code, i think if you took more breaks to clarify everything it would be even better, (like okay this is what we did up to this point) lovin it tho
I love how must really old news can make so much excitement😂
The "enum type" in rust is equivalent to the disjoint union type in F#, haskell, and ocaml which all inherit it from ML (Meta language not machine learning) defined and implemented in 1970.. so not a new thing at all.. the Standard ML (implementation) was already in 1970 comparable in speed to C, even though it used exotic things like a GC.. this should be taken with a grain of salt.. btw if you are unsure ML pre date haskell, and haskell is defined to be in the "ML family"
Awesome Prime, bring more differences and why Rust is better!!! First look enums seems the same in TS and Rust, but know I now there's a huge difference!!
Nice video man, I always used enums anyways. Whats the colorscheme btwm
pinerose
@@ThePrimeagen thanks
That comparison isn't accurate. In the switch example, you usually add a default case which contains an assertNever, so you catch that error. Or if your returning in every brach of the enum cases, definite returning checks will result in the same safety.
Regarding the union example: the behavior is due to JS. If you want to be more safe, most people use tagged unions (discriminated unions), which are the actual equivalent to Rusts enums (I think rust even does the same internally).
Some people also define their own result monad, like the Result in rust, based on tagged unions. In TS, you usually don't need the Optional monad, since you can just use T|null.
Yeah, enums in rust are cool. Way cooler than something like std::variant. But TS can be cool, too. Sometimes even cooler, with the control-flow-based type narrowing, which is something that rust sadly doesn't have.
damn, I was just learning these yesterday. As a typescript dev I am really loving the rust enums so far, especially the pattern matching!
Those enums are pretty close to java and java has an Optional as well as primitive pattern matching. Looks like rust would be pretty reasonable to learn.
Most languages are the same as Rust, C# for example is the same. Rust has become a religion almost followers are going crazy.
You can make ts enum switch case to also throw an error if not all cases are handled by using never in default.
Even despite this fact rust enums is still much better since you don't need to remember to always include default, and not just that.
enum Color {
Red,
}
function test(x: Color) {
switch (x) {
case Color.Red:
return;
default:
const test: never = x;
}
}
Thank the paradigms of functional programming which had this pattern matching. Rust adopts a lot of functional programming components!😊
Damn that was one solid video Prime. You've outdone yourself.
If you like this sort of thing you’d love Haskel and other pure functional languages
hah, i think i could end up liking it
@@ThePrimeagen indeed, Rust' type system is very similar to Haskell 2010 (but the later has higher kinded polymorphism). Both languages took Algrebraic Data Types (tagged enums with pattern matching) from Standard ML and OCaml. Haskell included type classes and typed families, named Traits and associated types in Rust if I am not mistaking. That being said, both languages are very different at the term level. And Haskell is GC'd... Also Haskell has more monads hahaha
But the question is: How can we have something like this in Typescript? or what is the best equivalent?