Rust Powered Polymorphism ⚡️ With Traits

  Рет қаралды 110,632

Code to the Moon

Code to the Moon

Күн бұрын

Пікірлер: 281
@Possseidon
@Possseidon 2 жыл бұрын
This would've probably went over the scope of what you were trying to show but for those interested: If you want anything that implements both `LandCapable` and `WaterCapable` to automatically implement `Amphibious` as well, you can do so: impl Amphibious for T {} Which can be read as "implement `Amphibious` for any type T that implements `LandCapable` and `WaterCapable`". There is also alias traits in unstable, that basically do more or less the same thing but with less boilerplate: trait Amphibious = LandCapable + WaterCapable;
@codetothemoon
@codetothemoon 2 жыл бұрын
Great point, I probably should have covered this as well - it would make things much more concise if you have lots of amphibious vehicles
@Singhrager
@Singhrager 2 жыл бұрын
@@mathijsfrank9268 I think you may be reading it the wrong way around. The example does not mean that being Amphibious implies being LandCapable. It means that, if you are LandCapable (regardless of whether you customize drive) and you are WaterCapable, that implies that you are Amphibious. So you still only have one implementation of drive, i.e. the one you go with when you implement LandCapable.
@tsalVlog
@tsalVlog 2 жыл бұрын
oh man, every day, after 5 years, I still learn something new about Rust.
@JorgetePanete
@JorgetePanete 2 жыл бұрын
gone*
@ythanzhang
@ythanzhang 2 жыл бұрын
You can also make T ?Size so it works on trait objects too. impl C for T {}
@mk72v2oq
@mk72v2oq 2 жыл бұрын
Worth mentioning that "prefer composition over inheritance" principle is general for any language. Rust just takes it as the standard and makes inheritance obsolete.
@codetothemoon
@codetothemoon 2 жыл бұрын
very true, good point! ditching inheritance makes code infinitely more readable imo...
@phenanrithe
@phenanrithe 2 жыл бұрын
That's a common misunderstanding of OO techniques. Composition and inheritances are two different patterns for two different needs (search for "has-a" and "is-a"), one doesn't simply replace the latter with the former. Rust just lacks inheritance at the moment, which leads to a class of issues for specific problems to solve, unfortunately. It's possible to work around but it requires to duplicate the code, which makes it hard to maintain. Or by using macros, which makes reading the code much more difficult.
@techpriest4787
@techpriest4787 2 жыл бұрын
Yes. Mostly. For game engine frameworks for instance you will need to store all data in one place like a vec for centralized storage so that you can do multi threading. That requires down casting which again requires up casting to Any first when you need access to data. For now up casting is an unstable feature. But it seems to work so far. The problem is that if you did cast to Any via your own functions inside a custom trait that is not Any. That you have to do that for any game node all over again because you can not make a default trait because of life time issues and seized issues. Horrible pain in the neck. But up casting is being stabilized so it is coming to stable Rust in the future.
@JorgetePanete
@JorgetePanete 2 жыл бұрын
@@phenanrithe Can you give examples? It would help
@ozanmuyes
@ozanmuyes 2 жыл бұрын
Is Rust even an object-oriented language?
@narwodev
@narwodev 2 жыл бұрын
Your clear and concise way of explaining things really helps me to learn more about Rust. Looking forward to the next episode...Thank you!
@codetothemoon
@codetothemoon 2 жыл бұрын
WOW thank you so much Mark!! I really appreciate your support and your kind words. Thanks again for watching!
@sergiuoanes4635
@sergiuoanes4635 2 жыл бұрын
Absolutely love your videos. Simple examples straight to the point. Keep them coming! thanks
@codetothemoon
@codetothemoon 2 жыл бұрын
wow thank you so much for your support and kind words! more to come!
@Julian-vi4vl
@Julian-vi4vl 2 жыл бұрын
One place where you really cannot escape the dynamic dispatch is when you have mixed types like a vector that can contain both SUV and Sudan
@shooohm405
@shooohm405 4 ай бұрын
Put both SUV and Sedan in an enum and use the enum in the vector.
@stefanmadzharov9170
@stefanmadzharov9170 2 ай бұрын
@@shooohm405 This is however trading memory for runtime performance if the structs have different memory footprints.
@Jason9637
@Jason9637 3 күн бұрын
​@@stefanmadzharov9170No it isn't. The vtable pointer is going to be bigger than any discriminant
@cd-bitcrshr
@cd-bitcrshr 2 жыл бұрын
Was stuck wondering how to do something in a Rust project, and you just went ahead and put the solution on a platter for me. Excellent video, as always.
@narigoncs
@narigoncs 2 жыл бұрын
Worth mentioning that `impl Trait` is just syntax sugar for `fn road_trip(vehicle: &T) {}`
@Jason9637
@Jason9637 3 күн бұрын
Which is just sugar for `fn road_trip(vehicle: &T) where T: LandCapable {}`
@fayaz2956
@fayaz2956 2 жыл бұрын
Whoa!! the way you explained the zero cost abstraction is mind blowing!!
@aditeya1024
@aditeya1024 2 жыл бұрын
I was writing a ray tracer in rust and this video was super helpful in explaining a trait!
@codetothemoon
@codetothemoon 2 жыл бұрын
nice, really happy that it helped! and props to you for tackling a ray tracer, that's quite an undertaking!
@Redditard
@Redditard 2 жыл бұрын
i hope you'll succeed and i'll be really happy if you'll let us know!!! all the besttt
@gaxkiller
@gaxkiller Жыл бұрын
What do you use to draw a single pixel on screen ? Was interested to learn rust doing a raytracer, even a basic one who does not use the gpu at first
@aditeya1024
@aditeya1024 Жыл бұрын
@@gaxkiller i use the ppm format, which just writes the rgb values of each pixel. Though I think you can use the image crate to convert to jpg/png
@gaxkiller
@gaxkiller Жыл бұрын
@@aditeya1024 Thx ! Ok so you write in a file, not on screen, perfectly fine but you cannot do "interactions" (move the camera, etc)
@janbaumann7794
@janbaumann7794 2 жыл бұрын
Really appreciate these videos. Keep up the good work :)
@codetothemoon
@codetothemoon 2 жыл бұрын
wow thank you so much for the support Jan!!! more to come!
@Kodlak15
@Kodlak15 2 жыл бұрын
This aspect of Rust has been really hard for me to wrap my head around. Perhaps even more so than ownership/borrowing/lifetimes. Thanks as always for the great content. This was helpful 😁
@codetothemoon
@codetothemoon 2 жыл бұрын
Nice, really happy it helped!
@nahiyanalamgir7056
@nahiyanalamgir7056 Жыл бұрын
I think it's because most people didn't learn these concepts of composition as beginners to programming. We instead swallowed OOP principles like that of Java. But things are changing and Rust is designed to be powerful, not simple and easy-to-learn.
@urisinger3412
@urisinger3412 4 ай бұрын
​@@nahiyanalamgir7056the first form of oop in java I learned as interfaces, which are really similar to traits
@BulbaWarrior
@BulbaWarrior 2 жыл бұрын
I think it's important to note a naming convention for traits used in rust: if your trait implements one function it should be named the same way as the function. So in this example idiomatic names for LandCapable and WaterCapable would be "Drive" and "Float". It is nice to know the convention as many of the standard traits are named this way (for example From and IntoIterator)
@sebastiangudino9377
@sebastiangudino9377 Жыл бұрын
Pretty sure the implications is that being "LandCapable" will do much more than just provide a single drive method. And on a small tangent. If your trait IS just what function. What's really the benefit os using a trait over just writing a generic drive function that you call as: drive(suv)? (Genuine question. Since I would be surprised if rust made some nice optimization in one case vs the other)
@BulbaWarrior
@BulbaWarrior Жыл бұрын
@@sebastiangudino9377 I think you are mixing things together. LandCapable is not a type, its a trait, so you can't pass it as a generic parameter. The correct call would be drive::(suv), but then think about what drive does: it has to work for all types that implement LandCapable, which means that you can only use functions from the LandCapable trait. But we have just decided to move the only function out of LandCapable, so drive can't really do anything meaningful now. Now let's look at why having a single function in a trait is a good thing. Suppose LandCapable has another method, I will call it fuel(). Now look at road_trip(): it only cares that its argument implements drive() and does not really care about fuel, so fuel() is redundant here, now imagine we have a bike that can't really be fueled. A better more flexible approach would be to have two traits: Drive and Fuel. Then functions that care only about drive will use just the first trait and some other functions will require both traits to be implemented - your code is more flexible! TLDR: think of traits not as objects but properties of objects, which work better when they are granular. Hopefully I made my point clear
@sebastiangudino9377
@sebastiangudino9377 Жыл бұрын
@@BulbaWarrior Ups yeah, i mixed the Syntax up quite a lot. But you thankfully understood what I meant! And yeah, I guess you are right. Rust is deeply related to composition. Weird at first. But seems like a really nice abstraction as things scale up
@sofroneageorgian7494
@sofroneageorgian7494 5 ай бұрын
At 7:28 I paused and said damn, this guy is really good at naming things.
@codetothemoon
@codetothemoon 5 ай бұрын
why thank you!
@ycombinator765
@ycombinator765 22 күн бұрын
this explanation is top tier. Exteremely simple to follow! THanks for sharing this with us.
@codetothemoon
@codetothemoon 21 күн бұрын
thank you, glad you got something out of the video!
@ygypt
@ygypt 5 ай бұрын
Every time I lookup something new that I'm learning, I have to wade through numerous videos with some guy talking forever about nothing and saying words I dont understand before finally stumbling across the quick and concise explanation that actually helps me. This time, I found it right away :)
@GlobalYoung7
@GlobalYoung7 Жыл бұрын
thank you
@codetothemoon
@codetothemoon Жыл бұрын
wow thank you so much for your support!!!!
@anuradhaamarasinghe9649
@anuradhaamarasinghe9649 Жыл бұрын
Oh man, I'm so glad that I subscribed to this channel. I think your explanation is obvious. Thank you and keep up the good work.
@codetothemoon
@codetothemoon Жыл бұрын
thanks so much for the kind words!
@ukaszlampart5316
@ukaszlampart5316 2 жыл бұрын
There are two very practical advantages of traits compared to inheritance base polymorphism: automatic implementation (if your type implements other specific traits), and automatic derivation. Because traits are seperate piece of code from your datatype it is ok to generate implementation for them automatically as this does not affect existing code base, compared to generating methods for interfaces.
@codetothemoon
@codetothemoon 2 жыл бұрын
great point!
@creativecraving
@creativecraving Жыл бұрын
This video helped me understand the difference between the dyn and impl syntax. Thank you!
@codetothemoon
@codetothemoon Жыл бұрын
nice, really happy you got something out of it!
@rct999
@rct999 Жыл бұрын
Tnx! This actually helped me understand the trait system in rust. I know 'traits' from PHP, but I never found a situation where it could be useful (its just horizontal inheritance basically). The way Rust uses traits makes much more sense to me.
@codetothemoon
@codetothemoon Жыл бұрын
nice! really happy the video helped you understand Rust traits!
@marcusrehn6915
@marcusrehn6915 Жыл бұрын
This feels like a far superior way to do OOP than what I am used to see in other languages.
@codetothemoon
@codetothemoon Жыл бұрын
I like it as well!
@olafk8232
@olafk8232 Жыл бұрын
What advantage do you mean?
@Tienisto
@Tienisto Жыл бұрын
It might be safer but it is not superior compared to traditional OOP languages because you need to write much more code
@marcusrehn6915
@marcusrehn6915 Жыл бұрын
@@Tienisto Compared to Java or C++?
@collynchristopherbrenner3245
@collynchristopherbrenner3245 5 ай бұрын
@@Tienisto The benefit though is that you get native readability, so readability is encouraged by the language instead of having to be implemented through discipline. This seems like a much better incentive structure for writing high quality (cleaner/more readable) code. Of course, Rust is still a complicated language, so there is a trade-off at some point.
@johndavidson8096
@johndavidson8096 2 жыл бұрын
Amazing video. You break down these rust concepts better than anyone else! Much appreciated as a TS/JS dev!
@wasabinator
@wasabinator 4 ай бұрын
Just getting into Rust and this clarified a lot from me. Thanks.
@codetothemoon
@codetothemoon 4 ай бұрын
Nice, really happy it was helpful for you!
@kippie80
@kippie80 2 жыл бұрын
Didn't realize &impl and &dyn were so interchangeable, thanks!
@codetothemoon
@codetothemoon 2 жыл бұрын
nice, glad you found it valuable!
@phenanrithe
@phenanrithe 2 жыл бұрын
They are not really interchangeable. Using "impl" is just syntactic sugar for a generic function, so as explained in the video the compiler will instantiate this function for each type that is used. This also means you cannot use it for example with a collection holding different types with the trait - for that you must use "dyn" and its virtual table (and that collection will also need to use fat pointers).
@Feyon
@Feyon 2 жыл бұрын
Very focused and clear explanation 👍 The impl instead of dyn was something new to me
@codetothemoon
@codetothemoon 2 жыл бұрын
Thank you, glad you found it valuable!
@alfredomenezes8814
@alfredomenezes8814 2 жыл бұрын
Very nice video, I love your Rust content, keep going!
@Xerofull
@Xerofull 2 жыл бұрын
I like your video style, its getting better with each one +1
@yondaime500
@yondaime500 2 жыл бұрын
One thing that is hard to do in Rust compared to other languages like C++ and C# is casting a trait to another trait. Like if you have a Box, you cannot check at runtime if the type stored in that variable also implements WaterCapable, whereas is C++ you can use dynamic_pointer_cast for that, and in C# you have the "is" and "as" keywords. I mention it because I've been rewriting code from those two languages to Rust, and I'm struggling to come up with the right patterns to replace these dynamic casts.
@PeterAuto1
@PeterAuto1 2 жыл бұрын
you could add a try_as_x() method to the trait, that in the default implementation returns None, but you can override it so it convers the type. like struct Foo; trait X { fn try_as_y(&self)->Option {None} } trait Y { fn try_as_x(&self)->Option {None} } impl X for Foo{fn try_as_y(&self)->Option {Some(self)}}} impl Y for Foo{ fn try_as_x(&self)->Option {Some(self)}}
@yondaime500
@yondaime500 2 жыл бұрын
@@PeterAuto1 It's just kind of awkward that I have to list out all the traits I want to be able to cast into, and then remember to override the cast function for every type that implements the corresponding trait. I had found some crates that apparently generate this boilerplate code with macros, but they don't have that many downloads, so I figured maybe I just shouldn't be doing that in the first place. But thanks for the tip anyway.
@heruhday
@heruhday Жыл бұрын
You could use trait downcast
@homelikebrick42
@homelikebrick42 Жыл бұрын
i know this is an old comment, but there is std::any::Any in the standard library for this exact thing
@yondaime500
@yondaime500 Жыл бұрын
@@homelikebrick42 Not quite. Any only allows casting to a concrete type. What I wanted was to cast a trait to another trait. For example, given a list of dyn Sensor, get all the items that implement the Thermometer trait, and then call a method from that trait. This is what is easy to do in C# and C++ but not in Rust. In Rust I have to add a method to Instrument with a default implementation (so that things that are not Thermometer don't have to implement it just to return an error), and then remember to override it where needed. It's kind of annoying. So now I'm trying to unlearn years of OOP so I can structure my code better to stop fighting against the language and avoid the problem altogether.
@HiltonFernandes
@HiltonFernandes 7 ай бұрын
Great explanation. Congrats !
@codetothemoon
@codetothemoon 7 ай бұрын
thank you!
@oglothenerd
@oglothenerd 7 ай бұрын
0:20 Why... why did you include that clip? My nerves are on fire.
@codetothemoon
@codetothemoon 7 ай бұрын
hah! it may have had the desired effect 🙃
@oglothenerd
@oglothenerd 7 ай бұрын
@@codetothemoon Oh you little...
@2002budokan
@2002budokan Жыл бұрын
Excellent small examples.
@codetothemoon
@codetothemoon Жыл бұрын
Thank you! 🙏
@ericleijonmarck
@ericleijonmarck Жыл бұрын
I love your videos, I like when you insert some images/videos to make it clear what you mean by landvehicle for instance. It is just a bit of alot of images switches in the video.
@codetothemoon
@codetothemoon Жыл бұрын
thanks for the feedback, we are always trying to make things entertaining while not being too obnoxious, sometimes that's a fine line to traverse!
@collynchristopherbrenner3245
@collynchristopherbrenner3245 5 ай бұрын
First time learning about traits in Rust after hearing such raving reviews from ThePrimeagen. And wow, how cool! This feels like the way polymorphism was meant to be done all along. It is a little strange that you couldn't put all three traits on the same line though. Now I'm wondering about the requirement of declaring before implementing or if they can be done at the same time. I already like Rust based on this one video.
@DrumMeister
@DrumMeister 2 жыл бұрын
Something which is weird is that the compiler gives ‘dyn’ as solution instead of the faster ‘impl’. That’s most likely because generics is harder to use for devs? Or what is the reason?
@codetothemoon
@codetothemoon 2 жыл бұрын
I was wondering about this as well, I'm actually not sure!
@DrumMeister
@DrumMeister Жыл бұрын
@@codetothemoon impressive answer from chatgpt 😜: “The Rust compiler does not necessarily prefer dyn over impl in function signatures. The use of dyn and impl has different implications and may result in better or worse outcomes depending on the situation. In general, impl is suitable for specifying the exact implementation details of a type, while dyn is suitable for specifying a trait object that exhibits a certain behavior but whose exact implementation is not important. In function signatures, the use of dyn or impl may depend on the exact details of the function and the user's needs. If a function requires a specific type, and its implementation is important for the function, impl may be more appropriate. However, if the function requires a certain behavior that can be provided by multiple types, dyn may be more suitable because it provides the user with more flexibility in the choice of type. It is important to understand the implications of impl and dyn and base the choice on the specific needs of the situation. In some cases, the use of impl may result in better outcomes, while in other cases, dyn may be more suitable.”
@ozanmuyes
@ozanmuyes 2 жыл бұрын
At 5:20 you said "Rust" which is lol because I'm here to learn about it 😀 Jokes aside good bite sized tuts, cheers
@codetothemoon
@codetothemoon 2 жыл бұрын
Thanks, glad you found it valuable!
@YuruCampSupermacy
@YuruCampSupermacy 2 жыл бұрын
loved the video, keep making more
@codetothemoon
@codetothemoon 2 жыл бұрын
thanks! more to come!
@ReedoTV
@ReedoTV 2 жыл бұрын
Had no idea super traits were a thing!
@codetothemoon
@codetothemoon 2 жыл бұрын
nice, love it when folks who already know about the video topic are still able to get value!
@ReedoTV
@ReedoTV 2 жыл бұрын
@@codetothemoon It's hard to find intermediate level content on Rust, so thank you for all the videos you make! I'm finding that going from being adequate at Rust to being good at it is a very long journey.
@hos7012
@hos7012 Жыл бұрын
thx for your effort what keyboard and IDE do u use?
@codetothemoon
@codetothemoon Жыл бұрын
thanks for watching! Keyboard is Corne v3 and IDE is DOOM Emacs
@Panakotta000
@Panakotta000 2 жыл бұрын
Dynamic dispatch is also extremely good when combined with Reference-Counting f.e. "Rc" and combined with Any we can even do some limited downcasting "prefer composition over inherintance" sure... but ngl... sometimes if you dont just have shared functionallity... but also shared data... it becomes a mess of delegations... which imo is not ideal...
@jwr6796
@jwr6796 4 ай бұрын
So is it correct to say that the trade-off between DYN and IMPL is a little bit of performance versus a little bit of extra binary size?
@codetothemoon
@codetothemoon 4 ай бұрын
That's usually the tradeoff, at least in the case of function parameters. But are situations where you might be forced to use dyn, as in the case where you'd like to make a vector of things for which you don't know the concrete type. And then I believe in the embedded world where there might not be a heap, you may be forced to use impl instead of dyn as well.
@jwr6796
@jwr6796 4 ай бұрын
@@codetothemoon thanks! 👍
@joshuarose3186
@joshuarose3186 Жыл бұрын
Hi there, i was wondering if you had a link to your dotfiles? Reason being, I love the way your emacs looks.
@barefeg
@barefeg 2 жыл бұрын
Would it be possible to implement amphibious directly without having to implement lang capable and water capable?
@nsgirish
@nsgirish Жыл бұрын
excellently explained
@codetothemoon
@codetothemoon Жыл бұрын
thank you, glad you liked it!
@jacekm.1789
@jacekm.1789 10 ай бұрын
amazing video. thank you so much!
@codetothemoon
@codetothemoon 10 ай бұрын
thanks, really happy you liked it!
@Bvngee
@Bvngee 2 жыл бұрын
Thanks for this! thought I knew the basics already. I didn't even know that &impl Trait existed, and I'm not even finished watching yet.
@jm-alan
@jm-alan 2 жыл бұрын
I've been working with Rust, learning on my own, for like a year now, and just today from this video learned that dyn is specifically referring to dynamic dispatch 😅 Like, duh, that makes perfect sense, but I just kinda took it as "dynamic means runtime processed aka vtable lookup" without stopping to think
@codetothemoon
@codetothemoon 2 жыл бұрын
nice, really glad you got something out of the video, despite likely already being familiar with many of the concepts!
@JosephDalrymple
@JosephDalrymple 2 жыл бұрын
Building my first REST API using axum and sqlx, and I wanted to use `traits` in order to be able to swap out instances of certain aspects for their mock equivalents. Unfortunately, since so much of the code requires `async`, this proved to be impossible. I know in the nightly compiler there's _some_ support for async trait members, but I'm honestly more interested in getting myself to a place where I can optimize away most of the `async` to make things more testable. I started my career in C/C++, and then moved to Front End in the latter portion of my career, where I've become addicted to 80% Test Coverage minimums in the professional space, and 100% test coverage minimums in my personal projects. This has proved to be _quite_ the exercise moving back to strongly typed languages haha: Almost exclusively due to mocking. I'm a huge advocate of simple input-output and keeping most functions as simple as possible in order to make them easier to test. In the frontend space, it's super easy to swap out a struct with something that _looks_ the same, but functionally isn't. This has proven quite the task in Rust 😂
@JosephDalrymple
@JosephDalrymple 2 жыл бұрын
I see more and more "Integration-style Tests" in Rust and C/C++ code bases than Unit Tests, which I feel adds complications which cloud the purpose of the function and the tests, making the code less stable overall.
@levizin917
@levizin917 2 жыл бұрын
If you dive into rust for pratical uses you need to turn everything into async, so don't worry about that and do use async traits, also traits are really useful for mocking and testing and my company uses it all the time. But also makes so your struct has this contract (the trait) that tells you what it needs to implemento to be used for your porpose. This way you can always add new providers or mantain your code using this trait that tells you what your code needs to do. Here is one example: Imagine your service will hire a payments api service, and you build a Client for it that is able to call all the api's of the service. This endpoints are from your provider and there is no personal logic of yours. Now you need to not only call a endpoint, but multiple, or transform data before using it. This logic will go in your trait PaymentProvider or something like that. Another thing that can be useful for doing this is. Imagine that this Client struct is used by many services in your company. But your service only use a few of this endpoints. In your personal service trait you will only specify those endpoints that you need. My point is that this traits that are placed for mocking will be used for other reasons
@levizin917
@levizin917 2 жыл бұрын
@@JosephDalrymple About this integration-style tests I can say that usualy mocking is always the way for calling other services or providers and only testing integration with your database is useful, which always is easy to replicate for testing and doesn't make it unstable
@JosephDalrymple
@JosephDalrymple 2 жыл бұрын
​@@levizin917 Unfortunately, spinning up, populating, and spinning down a database tends to be heavy, and shouldn't be done as a regular test of your codes functionality. These tests are great because they're End-To-End, but Unit Tests should make up the bulk of tests for any given application. Unit Tests typically test a single function at a time. But this can be difficult when async traits are not yet fully supported in Rust. While there are workarounds in the meantime, the problem in and of itself is already quite a complex one to solve, given the need to calculate lifetimes beyond what is currently done for structs with standard methods. Because of this, its not a trivial task to pivot from concrete async structs to dynamic async traits, especially when the only gain comes in the testing world. Most of what I've done to alleviate that is to create #[cfg(test)] and #[cfg(not(test))] implementations of my structs, which is a major pain, but it gets around having to deal with the immense overhead of introducing modular functionality just for testing purposes, when there isn't much else to gain. A more attractive solution would be the ability to define a mod.mock.rs or something to define the mock implementation of a struct for testing purpose. It's just not worth the overhead to introduce additional heap allocations simply to make testing more intuitive. That has unnecessary real-world implications on your application's performance.
@levizin917
@levizin917 2 жыл бұрын
@@JosephDalrymple I can only atest to how we do things at my job, whe usually use traits with async_trait library, and mock with mockall for unit testing. the services dont have any problem and no problems in performance.
@nickpatella1525
@nickpatella1525 Жыл бұрын
Darn, I didn't even realize you could choose between dynamic dispatch and static dispatch so concisely. And I didn't know about supertraits.
@danielgerlach5141
@danielgerlach5141 2 жыл бұрын
Great video about rust traits, especially the super trait was very interesting. Of topic question: what editor do you use? I remember you used vscode, but now it seems you switched to (neo)vim? Btw it also seems you have a new keyboard - not so clicky and easier on the ears for the video 👍
@awdsqe123
@awdsqe123 2 жыл бұрын
The editor is doom emacs.
@codetothemoon
@codetothemoon 2 жыл бұрын
thanks, really glad you liked it! I'm currently using DOOM emacs which I'm really enjoying at the moment. And I am also trying a new keyboard called a Corne - it's pretty amazing and I can't see myself going back at this point
@codeshowbr
@codeshowbr 2 жыл бұрын
@@codetothemoon do you have your doomemacs config shared somewhere? I tried to enable inlay hints but failed.
@codetothemoon
@codetothemoon 2 жыл бұрын
@@codeshowbr actually i don't believe I did anything special other than uncommenting (rust +lsp) in init.el, and I *think* also uncommenting "lsp" in the "tools" section
@syumjoba
@syumjoba Жыл бұрын
cool quick tutorial, just found out about dyn and impl
@codetothemoon
@codetothemoon Жыл бұрын
thanks glad you got something out of it!
@Taurdil
@Taurdil 2 жыл бұрын
What kind of dynamic dispatch does Rust have though? Single(as Java, C++,C#, etc) or Multiple (CLisp) ? I mean, say we now have super trait "Surface" and "Road" and "Ice" extends it. Then 'drive' would take "&dyn Surface" and, say, would print "Driving/Floating on {surface.name()}".
@mk72v2oq
@mk72v2oq 2 жыл бұрын
Here is the test, if I got it right. Code: #![feature(trait_upcasting)] trait Surface { fn name(&self) -> &str { "unknown surface" } } trait Road: Surface { fn name(&self) -> &str { "road" } } trait Ice: Surface { fn name(&self) -> &str { "ice" } } struct Street {} impl Surface for Street {} impl Road for Street {} struct Glacier {} impl Surface for Glacier {} impl Ice for Glacier {} fn print(surface: &dyn Surface) { println!("Driving/Floating on {}.", surface.name()); } fn main() { print(&Street {} as &dyn Road); print(&Glacier {} as &dyn Ice); } Output: Driving/Floating on unknown surface. Driving/Floating on unknown surface.
@biskitpagla
@biskitpagla 2 жыл бұрын
Rust has single dispatch, an influence from C++. Bjarne has written at length about the difficulties of implementing multiple dispatch in a systems language.
@DaddyFrosty
@DaddyFrosty 2 жыл бұрын
Not sure what the curve ball was but I do think that it’s great that rust lets you generate templated versions of functions. But at the end of the day a VTable lookup isn’t the end of the world.
@codetothemoon
@codetothemoon 2 жыл бұрын
The curve ball was that you can't just use a trait as a parameter type, you have to specify 'dyn' or 'impl'. In most languages that's a decision that you don't have to make.
@DaddyFrosty
@DaddyFrosty 2 жыл бұрын
@@codetothemoonfair enough 👍
@renxula
@renxula 2 жыл бұрын
Woah, how does your "cargo run" compile it in 0.11s? I just got mine to compile a trivial program in 2.5s instead of 4.5s by changing the linker. (This was in WSL2.) Now that I know it CAN be fast, I want to make it that fast! 2 seconds is long enough to get bored...
@codetothemoon
@codetothemoon 2 жыл бұрын
Not sure, I haven't done anything to deliberately make it faster. I am on a 1 year old M1 macbook pro, not sure if it's just because of the hardware
@renxula
@renxula Жыл бұрын
@@codetothemoon Thanks anyway - when I saw that compilation can be fast, I went searching for answers. It turns out that WSL2 was indeed my problem: accessing files from the NTFS side is quite slow. (It doesn't normally feel THAT slow, but I guess cargo or rustc accesses a LOT of files.) The solution is to move the source files to the Linux filesystem, or run the Rust compiler on Windows. VS Code can edit the files inside WSL, too. Btw, here's a hint for you, when you use rust-analyzer with VS Code: it shows the inferred types of local variables by default, but those can be hidden, as well as function parameter names. I find those to be spammy and super distracting, and I can get the same info if I need it, by hovering over the text :)
@grahamcracker1234
@grahamcracker1234 2 жыл бұрын
Great video, just wanted to let you know that for struct naming semantics when you have multiple capital letters next to each other you are actually only supposed to capitalize the first one, e.g. Suv not SUV, Html not HTML
@GlobalYoung7
@GlobalYoung7 Жыл бұрын
thank you 👍⚡️
@codetothemoon
@codetothemoon Жыл бұрын
thanks for watching!
@dimak7769
@dimak7769 Жыл бұрын
Tnanks, just awesome!!! VERY IMPORTANT QUESTIONS: 1. What is the name of your VS Code theme? 2. How did you make highlight the current line number?
@antifa_communist
@antifa_communist 10 ай бұрын
It's not VSCode, it's doom emacs. Not sure exactly what that is, but he said it in another comment.
@delir0
@delir0 Жыл бұрын
Have anyone mentioned the most "Rusted" variant for the function? fn road_trip(vehicle: &T). This also allows us to make the function traverse_frozen_lake without making any "aggregation" traits (Amphibious). Just like that: fn road_trip(vehicle: &T)
@RichardBurgess-v2h
@RichardBurgess-v2h Жыл бұрын
Is there a problem putting a function inside an impl block without a "self" in order to associate it with that group, kind of like a class method would be? How would I otherwise implement something that is like a class method?
@xenocampanoli815
@xenocampanoli815 Жыл бұрын
Looking all around for examples of a Vec or other collection contains a bunch of different subtraits, which in your case would be vehicles. Vec. Temporarily stuck on this.
@haraldbackfisch1981
@haraldbackfisch1981 10 ай бұрын
I know this is an old question but I had to do sth similar lately. I just created an enum which variants contain the things with different traits. Then you can have a vector of this enum and can match over the enum to get to the desired element (subtype).
@АртемФедоров-ю7б
@АртемФедоров-ю7б Жыл бұрын
This is common use case when you need to implement some behaviour which uses some data + also you want to have some structs sharing some field sets. Instead you invent a wheel in rust to achieve that, by implementing getters/setters to use them in default implementation
@Bvngee
@Bvngee 2 жыл бұрын
I've noticed you seem to be editor-hopping a lot :P first VSCode, then nvim, then helix, now doom emacs?? What are your thoughts on what you'll settle with or is this just for fun?
@TheToric
@TheToric 2 жыл бұрын
You are correct in that rust does not consider itself object orienyed, as rust consideres object orientation an antipattern. Rust olis functional/procedural.
@codetothemoon
@codetothemoon 2 жыл бұрын
Some would argue that using polymorphism is "object oriented programming". I think the lines are a bit gray here.
@bradywb98
@bradywb98 Жыл бұрын
“Objects” are no different than structs in Rust. You’ve got a memory region with a set of data in it. You’ve got a collection of operations the compiler will allow you to perform on that region. There is nothing special about objects.
@bradywb98
@bradywb98 Жыл бұрын
The conversation behind classes and inheritance is different. But to associate “objects” with those ideas is IMO wrong.
@nirajgautam403
@nirajgautam403 11 ай бұрын
Can we use vars from base struct in derived one?
@befosocial
@befosocial Жыл бұрын
I really thought Emacs has gone extinct, but it seems to have one last user.
@codetothemoon
@codetothemoon Жыл бұрын
Lol 😂 I’m definately not one of those folks who is married to their editor, give me an alternative that has org mode and supports multiple fonts in the same buffer and I’ll consider switching 🙃
@befosocial
@befosocial Жыл бұрын
@@codetothemoon I definitely am one of those, but I've chosen the only good and bright side there is. 🤣
@codetothemoon
@codetothemoon Жыл бұрын
@@befosocial you're referring to Notepad I'm assuming? 😎
@persianmaster400
@persianmaster400 Жыл бұрын
It seems to me adding impl WaterCapable and impl LandCapable for Hovercraft is redundant since the Hovercraft is Amphibious which is defined already as both WaterCapable and LandCapable. Could you please explain why we still need to add those?
@digama0
@digama0 Жыл бұрын
The supertrait bound only means that any type which implements Ambhibious is required to also implement WaterCapable and LandCapable, it doesn't do the implementation for you (not least because the implementation usually has functions in it which you are supposed to write). If you wanted to get an automatic implementation, you would not have "trait Ambhibious: WaterCapable + LandCapable" but instead have "impl WaterCapable for T { ... }", and this implementation would be used even if you only have "impl Ambhibious for Foo". But beware, if you do this then you will not be allowed to also write "impl WaterCapable for Foo", as this would result in two implementations of WaterCapable for Foo and rust doesn't like that.
@rainerwahnsinn3262
@rainerwahnsinn3262 Жыл бұрын
I think you should have mentioned that `` is the normal syntax for a trait bound, and `impl MyTrait` is just a shorthand with the limitation that you can't reuse it in multiple places, e.g. as both argument and return type.
@goodwish1543
@goodwish1543 Жыл бұрын
Easy to read. May I ask a question: what's your workaround on Trait object with generic function parameter? Why this kind of Trait object is unsafe?
@TheLetsComment
@TheLetsComment Жыл бұрын
7:55 you could simply use a Trait Alias, since the Amphibious Trait has no methods (trait Amphibious = LandCapable + WaterCapable;)
@pookiepats
@pookiepats 3 ай бұрын
Incorrect
@Mike-zx7lq
@Mike-zx7lq 6 күн бұрын
I love the explanations. I find the jumps to stock footage distracting when I'm trying to focus on ingesting new technical concepts, though. I have to try to actively ignore them.
@codetothemoon
@codetothemoon 6 күн бұрын
glad you found the video valuable, and thanks for the feedback - it really helps!
@michaelsohnen6526
@michaelsohnen6526 2 жыл бұрын
What is the difference between static dispatch and generics with trait bounds? Im a beginner and have never even seen the use of 'impl' in a rust function signature.
@mvargasmoran
@mvargasmoran 2 жыл бұрын
like your style.
@codetothemoon
@codetothemoon 2 жыл бұрын
Thanks, much appreciated!
@pixelstriko1642
@pixelstriko1642 2 жыл бұрын
As soon as i saw you copy pasting the drive method. I screamed 'USE A TRAIT!!'
@codetothemoon
@codetothemoon 2 жыл бұрын
hah, you knew what was coming!
@adicide9070
@adicide9070 Жыл бұрын
I think I missed the twist :D was it the impl vs dyn? :)
@guilherme5094
@guilherme5094 2 жыл бұрын
👍Thanks!
@codetothemoon
@codetothemoon 2 жыл бұрын
thanks for watching!
@razvbir
@razvbir 2 жыл бұрын
Took me a while to notice that you are using doom emacs
@codetothemoon
@codetothemoon 2 жыл бұрын
indeed, I've been pretty happy with it lately
@razvbir
@razvbir 2 жыл бұрын
@@codetothemoon Your video on helix made me try it. Any plans to cover doom emacs in a future video?
@danielolili
@danielolili Жыл бұрын
Best thing I have learned today. super traits. for that reason, I subscribe,
@chris.davidoff
@chris.davidoff 2 жыл бұрын
I'm really curious what the performance difference of impl vs dyn really is. I suppose this would be a good mini-challenge/project for me to do :P
@codetothemoon
@codetothemoon 2 жыл бұрын
yeah, it would be an interesting test - i'd be shocked if nobody has posted the results of such a test yet...
@football-is-divine
@football-is-divine Жыл бұрын
Which theme is that? 😮
@bhavyakukkar
@bhavyakukkar Жыл бұрын
monokai
@lautaroblasco
@lautaroblasco Жыл бұрын
Good video
@codetothemoon
@codetothemoon Жыл бұрын
thank you!
@MTrax
@MTrax 11 ай бұрын
Gosh I really thought you were the typing god himself until I realized that it’s sped up
@rya-q6e
@rya-q6e Жыл бұрын
very nice
@codetothemoon
@codetothemoon Жыл бұрын
thank you!
@bradywb98
@bradywb98 Жыл бұрын
I don’t think having to annotate parameters as being “dyn” is an example of a ZCA. This is just the compiler requiring you to… actually specify the parameter type. A trait is not a type, it’s just a constraint. Types describe the structure of some set of data of memory. Traits are just descriptions of the operations you can perform on some unknown set of data. The data being passed as the argument is completely different for dyn and non-dyn parameters. The former is a fat pointer to a vtable and to an object. The latter is the full set of data (or a pointer to it if we’re using references). Hence these are different types. “dyn” is a type qualifier just like “mut” is and the compiler is not being overly picky by requiring you to use it.
@JosephDalrymple
@JosephDalrymple 2 жыл бұрын
I'm curious if the Rust community would be interested in the capability to Copy instead of using Fat Pointers. In other words, allow the compiler to be modified in such a way that the project you're building (maybe not the dependencies, since they weren't built with that option) to choose where the cost is incurred. Granted, that would essentially turn Traits into a type of Generics.
@jrmoulton
@jrmoulton 2 жыл бұрын
Good video. Why the switch to emacs? Also random note in case you've never seen it, Control-l will clear the terminal screen without having to type clear.
@codetothemoon
@codetothemoon 2 жыл бұрын
thanks! I had been using VSCode just for the videos because it seemed like thats what most of the viewers are using, while using neovim behind the scenes. I switched to doom emacs and decided I really liked it, and haven't felt especially compelled to switch back to neovim. Shortly thereafter I decided to try using emacs in the videos as I figured it probably would't bother the VSCode folks - hopefully that is indeed the case 🙃 Thanks for the Ctrl-I tip, I'm constantly finding gaping holes like this in my knowledge of shortcuts!
@zzzyyyxxx
@zzzyyyxxx 2 жыл бұрын
@@codetothemoon only the code matters, not the editor you use, so keep using whatever editor you'd like, doesn't bother us
@jrmoulton
@jrmoulton 2 жыл бұрын
@@codetothemoon Makes sense. I think they've all looked great in the videos.
@rGxDale
@rGxDale Жыл бұрын
What editor and theme is that? its fkin beautiful
@bhavyakukkar
@bhavyakukkar Жыл бұрын
doom emacs, monokai-classic
@Erhannis
@Erhannis Жыл бұрын
I emitted quite a strange noise at the clip art of somebody washing a circuit board
@raphaeljaggerd3585
@raphaeljaggerd3585 Жыл бұрын
Its like inheritance had composition had a baby but composition had stronger genetics.
@codetothemoon
@codetothemoon Жыл бұрын
LOL that's a very good description of the approach Rust takes 😎
@raphaeljaggerd3585
@raphaeljaggerd3585 Жыл бұрын
@@codetothemoon I'm not a rust developer but i just realized ive been subconsciouslly learning Rust through your videos. It now feels less intimidating, thank you so much for sharing your knowledge with us.
@JacobNax
@JacobNax 8 ай бұрын
Inheritance is such a pain in the ass... I'm so glad i started learning Rust and moving away from foolery (oop, nulls)
@anotherelvis
@anotherelvis 6 ай бұрын
I would prefer to name the trait Drive, so that the trait name is the same as the provided method.
@codetothemoon
@codetothemoon 5 ай бұрын
ahh great suggestion, I think I'd like that better as well.
@larrymarso4492
@larrymarso4492 2 жыл бұрын
Very nice! Now do trait objects.
@youseft.3141
@youseft.3141 Жыл бұрын
that is what dyn are
@handsanitizer2457
@handsanitizer2457 2 жыл бұрын
2nd interesting thanks
@codetothemoon
@codetothemoon 2 жыл бұрын
glad you liked it!
@bombrman1994
@bombrman1994 11 ай бұрын
providing code would be nice
@DJenriqez
@DJenriqez 8 ай бұрын
Now be a man and show how to cast elements in HashMap where there are 3 types in one map, Entity, Station, Buffer,... types can interact with each other... so you have to cast them to specific type.
@verified_tinker1818
@verified_tinker1818 2 жыл бұрын
Since when is Rust object-oriented? I thought it was a procedural language with functional bits.
@peter9477
@peter9477 2 жыл бұрын
It's not a class-based OOP language, but that's not an absolute requirement to be considered OO.
@samuelhurel6402
@samuelhurel6402 2 жыл бұрын
If the lake is frozen, why would we need to float ? ;p
@ErikBongers
@ErikBongers Жыл бұрын
My main takeaway....English doesn't have a general verb to describe a travelling boat! There's 'to sail', but nothing more general. Luckily Nelson died before having to command engine driven boats. Or did he?
@brunomello7499
@brunomello7499 Жыл бұрын
You type hella fast
@codetothemoon
@codetothemoon Жыл бұрын
that fast forward makes me look like a competent typer!
@aryabp
@aryabp 2 жыл бұрын
bruh i tought rust now driven by NATO
@headlibrarian1996
@headlibrarian1996 7 ай бұрын
Those empty impl blocks for composed traits seem dumb.
@RogasTV
@RogasTV 2 жыл бұрын
Please consider facilitating object oriented programming in other languages. Rust should be used in a more functional style. Having said that, it was a very good explanation! Thank you! Btw, C++ does not have generics.
@biskitpagla
@biskitpagla 2 жыл бұрын
Rust's traits system *is* based on some OO ideas. I don't understand what you're trying to achieve by abstaining from Rust's premier construct for polymorphism. The language is clearly multiparadigm and you're only going to end up writing non-idiomatic code if you're in denial of that. Your comment about C++ also doesn't make sense. A project like STL was authored in C++ specifically because it had the best generics support you could get in a systems language at that time, even though STL's author preferred functional over the other paradigms. STL is also based on OO ideas, excluding inheritence. Of the OO ideas Rust took from C++, an STL inspired standard library and traditional oo single dispatch, which the traits system uses, come to mind. Rust is oo for the same reason C++ is, it just makes sense to encapsulation remaining state when you're done with the functional and pure part of your program. This is a natural evolution of systems languages that also target the application realm. I don't think there's any value in denying this.
@bradywb98
@bradywb98 Жыл бұрын
The hive mind doesn’t know what they’re talking about at this point. What is special about an “object” in C++ vs a struct instance in Rust? Answer: nothing. An object is just a set of data in memory that can have certain operations performed on it. A struct instance if just a set of data in memory that can have certain operations performed on it. There is nothing special about “objects”. Using polymorphism has nothing to do with “object orientation”. Rust’s enums, traits, and generics all work with “objects” but those are premier features of the language. You can’t write any code without having complex structured sets of data and defined operations for them. These are objects. People see “OOP” and “Rust” in the same sentence and their brain cells dissolve.
Rust Interior Mutability - Sneaking By The Borrow Checker
16:02
Code to the Moon
Рет қаралды 77 М.
Rust Demystified 🪄 Simplifying The Toughest Parts
14:05
Code to the Moon
Рет қаралды 194 М.
人是不能做到吗?#火影忍者 #家人  #佐助
00:20
火影忍者一家
Рет қаралды 20 МЛН
黑天使被操控了#short #angel #clown
00:40
Super Beauty team
Рет қаралды 61 МЛН
How Strong Is Tape?
00:24
Stokes Twins
Рет қаралды 96 МЛН
Mom Hack for Cooking Solo with a Little One! 🍳👶
00:15
5-Minute Crafts HOUSE
Рет қаралды 23 МЛН
Two Ways To Do Dynamic Dispatch
19:54
Logan Smith
Рет қаралды 87 М.
but what is 'a lifetime?
12:20
leddoo
Рет қаралды 90 М.
Using polymorphic async closures in rust
9:50
MathiasCodes
Рет қаралды 2,3 М.
Using Trait Objects in Rust
13:32
Let's Get Rusty
Рет қаралды 42 М.
Rust Data Modelling Without Classes
11:25
No Boilerplate
Рет қаралды 187 М.
8 deadly mistakes beginner Rust developers make
14:14
Let's Get Rusty
Рет қаралды 182 М.
Ace Rust Macros ♠️ the declarative kind
14:06
Code to the Moon
Рет қаралды 42 М.
Arc instead of Vec? | Prime Reacts
37:18
ThePrimeTime
Рет қаралды 71 М.
Rust's Alien Data Types 👽 Box, Rc, Arc
11:54
Code to the Moon
Рет қаралды 158 М.
Andrew Kelley   Practical Data Oriented Design (DoD)
46:40
ChimiChanga
Рет қаралды 169 М.
人是不能做到吗?#火影忍者 #家人  #佐助
00:20
火影忍者一家
Рет қаралды 20 МЛН