Just found your channel last Friday. I'm still learning. Right now I can't escape the hell of having my match arms types that don't match. I'm taking a break to watch this.
This is so good man! Love this video and your content. I personally appreciate that you have those articles of some very root sources present in you video.
I have 10yoe but new to learning rust, thanks for making so much content, we are writing our AWS backend with lambdas in rust. I think you could get way more views if you rename your videos to other programming concepts. Like interfaces, oop and mocking in rust. As a newbie in rust, I don’t search for the correct rust terms because I don’t even know them yet. Just something to think about.
I agree, that's a good idea to visualize it. Try to think of it in terms of behaviors instead of objects. Even though the term "dynamic dispatch" is confusing in and of itself, try to ignore the terminology and focus on the simple concept that it actually is! You'll get it, just practice a few times with different concepts. 🙂
We need to always qualify the runtime cost of dynamic dispatch or v-table calls as miniscule, and for 99% of engineers, ignorable. If your code isn't running in a tight loop over millions of objects that need to be processed in realtime, then don't worry about it. The performance hit is CPU and a vast majority of code written isn't bound or bottlenecked by the CPU.
I'd like to see more real usage examples, the only time I found trait objects useful were for implementing type reflection and runtime type information, still a great video!
Thank you! That's a fair point. I have some ideas where abstractions could be useful. For example: imagine you're building an application that uploads a local filesystem path to cloud storage. That cloud storage could be Azure Blob Storage or Amazon S3. These services use different APIs. You could use a Trait to define a common "upload_file()" or "download_file()" behavior, and accept a Trait that abstracts the underlying storage provider. I'd have to think a bit more about how exactly I'd go about implementing that, but hopefully that gives you a practical example of where abstractions are useful.
Great video, thank you! I'm pretty sure I'm missing something, but I'm confused as to why we need to use this feature; is it only to reduce the binary size? Because seems like the "normal" way of doing things seems more intuitive 🤔
The example at 8:38 shows a good reason to use this. Sometimes you and the compiler don't know what trait object will be returned and so it's literally impossible to choose the correct implementation of that trait at compile time. Remind yourself that with monomorphism two different structs that implement the same trait are totally different at compile time, so returning some 'Number' that has a function of 'square()' would be akin to e.g. returning either a u8 or f64, they have totally different sizes so can't both be allocated on the stack and furthermore they have a completely different implementation to square. So now you must return a heap reference with a dynamic trait (Box) in order to dynamically choose the correct squaring implementation at runtime. Basically, the dyn keywords makes it at all possible to have polymorphism, which can be incredibly useful even with Rust's emphasis on monomorphism, traits and enums. (another way to write the above example would be to make an enum Number{Float(f64), Int(u8)} and then return the enum and make a function square(number: Number) => Number that matches all the variants and squares their contents, but this requires a match statement and therefore requires you to change your code everywhere once you add another type of number)
very good tutorial but there seems to be some flaw that can do with a bit of refinement : The get_animal() function definition should be more general ..were instead of having to change the content for the function definition we can simply supply the function with a parameter of the animal object eg: get_animal(animal_name). so that the function definition looks like :::... fn get_animal(animal_name)->Box{ Box::from(animal_name ) } I just dont know how to do it... is it possible ??
Thanks, and that's a good question. I am not sure how that would be accomplished. Generics are somewhat limited in Rust, and are still being developed, as I understand it.
Just found your channel last Friday. I'm still learning. Right now I can't escape the hell of having my match arms types that don't match. I'm taking a break to watch this.
This is so good man! Love this video and your content. I personally appreciate that you have those articles of some very root sources present in you video.
I have 10yoe but new to learning rust, thanks for making so much content, we are writing our AWS backend with lambdas in rust.
I think you could get way more views if you rename your videos to other programming concepts. Like interfaces, oop and mocking in rust.
As a newbie in rust, I don’t search for the correct rust terms because I don’t even know them yet. Just something to think about.
This is actually really good feedback.
IMO a graphical illustration of the Dynamic Dispatch might be easier to understand. I am still getting my head around this concept :)
I agree, that's a good idea to visualize it. Try to think of it in terms of behaviors instead of objects. Even though the term "dynamic dispatch" is confusing in and of itself, try to ignore the terminology and focus on the simple concept that it actually is! You'll get it, just practice a few times with different concepts. 🙂
We need to always qualify the runtime cost of dynamic dispatch or v-table calls as miniscule, and for 99% of engineers, ignorable. If your code isn't running in a tight loop over millions of objects that need to be processed in realtime, then don't worry about it. The performance hit is CPU and a vast majority of code written isn't bound or bottlenecked by the CPU.
I think supertraits should be called compound traits. It is more descriptive
Thanks!
I'd like to see more real usage examples, the only time I found trait objects useful were for implementing type reflection and runtime type information, still a great video!
Thank you! That's a fair point. I have some ideas where abstractions could be useful. For example: imagine you're building an application that uploads a local filesystem path to cloud storage. That cloud storage could be Azure Blob Storage or Amazon S3. These services use different APIs. You could use a Trait to define a common "upload_file()" or "download_file()" behavior, and accept a Trait that abstracts the underlying storage provider. I'd have to think a bit more about how exactly I'd go about implementing that, but hopefully that gives you a practical example of where abstractions are useful.
great tutorial !!!
Great video, thank you!
I'm pretty sure I'm missing something, but I'm confused as to why we need to use this feature; is it only to reduce the binary size? Because seems like the "normal" way of doing things seems more intuitive 🤔
Great question! I'm still trying to figure that out for myself. Maybe you can find he best answer!
The example at 8:38 shows a good reason to use this. Sometimes you and the compiler don't know what trait object will be returned and so it's literally impossible to choose the correct implementation of that trait at compile time.
Remind yourself that with monomorphism two different structs that implement the same trait are totally different at compile time, so returning some 'Number' that has a function of 'square()' would be akin to e.g. returning either a u8 or f64, they have totally different sizes so can't both be allocated on the stack and furthermore they have a completely different implementation to square. So now you must return a heap reference with a dynamic trait (Box) in order to dynamically choose the correct squaring implementation at runtime.
Basically, the dyn keywords makes it at all possible to have polymorphism, which can be incredibly useful even with Rust's emphasis on monomorphism, traits and enums.
(another way to write the above example would be to make an enum Number{Float(f64), Int(u8)} and then return the enum and make a function square(number: Number) => Number that matches all the variants and squares their contents, but this requires a match statement and therefore requires you to change your code everywhere once you add another type of number)
very good tutorial but there seems to be some flaw that can do with a bit of refinement : The get_animal() function definition should be more general ..were instead of having to change the content for the function definition we can simply supply the function with a parameter of the animal object eg: get_animal(animal_name). so that the function definition looks like :::...
fn get_animal(animal_name)->Box{
Box::from(animal_name )
}
I just dont know how to do it... is it possible ??
Thanks, and that's a good question. I am not sure how that would be accomplished. Generics are somewhat limited in Rust, and are still being developed, as I understand it.
@@TrevorSullivan thank you.
I wonder if all this complexity is due to the fact that rust does not implement classes....
its more powerful than classes. you can implement your own trait for some external struct or even for i32 which is impossible for classes