Crust of Rust: Dispatch and Fat Pointers

Поделиться
HTML-код
  • Опубликовано: 21 ноя 2024

Комментарии • 90

  • @10e999
    @10e999 3 года назад +85

    I'm currently starting the Crust of Rust series from the start.
    Just here to thank you for your work.
    The topics are interesting and your examples /explanations well crafted.

  • @omelettttttteeeeeee
    @omelettttttteeeeeee 3 года назад +40

    This is some of the highest quality rust content I’ve seen. Thanks for your work and knowledge-sharing!

  • @TheKaratekidd32v
    @TheKaratekidd32v 3 года назад +27

    Thanks for adding timestamps to these videos! It makes it easy to watch a couple 'chunks', and come back to the video later.

  • @chrisboyce5009
    @chrisboyce5009 3 года назад +15

    These videos are great! For me, the first third is usually "I totally understand what's going on", next third is "I understand some of these words", and make it another 10-15 minutes before starting the video over. The Q&A is really helpful too, since someone in the chat always asks about a specific corner case or exception. It doesn't seem like there is a lot of good intermediate-level material out there, so I'm always excited to see a new video.

  • @revanthshalon5626
    @revanthshalon5626 4 месяца назад

    I came here after reading the book Rust for Rustaceans and this helped me understand a lot better. Thanks a lot Jon!

  • @touisbetterthanpi
    @touisbetterthanpi 3 года назад +3

    You don’t even know how helpful this particular episode has been for me. And the detailed chapter markers too have been so nice when I need to refer back. Seriously. Thank you

  • @ihasmax
    @ihasmax 2 года назад +1

    I really appreciate that you touch on very advanced topics while teaching beginner/intermediate ones. I've learned the most from your videos so far and have a deeper understanding of how Rust actually works

  • @Loige
    @Loige 3 года назад +6

    Excellent video as usual! Thanks, Jon. I feel like dynamic dispatch and its constraints make a lot more sense to me now!

  • @KaranKumar-wb5bn
    @KaranKumar-wb5bn Год назад

    32:55 this has to be the best explanation.
    I literally had this doubt and I was about to google how a function would know the size of normal array otherwise. But you explained it so well right after that. Thank you so much for these videos.

  • @SaintlySpirit
    @SaintlySpirit 3 года назад +8

    For those, who prefer visualizations over the long documentation text, visit cheats.rs. For example, the idea of fat pointers can be grasped from the cheats.rs/#references-pointers-ui section. Of course, this site is pretty much of any value if you already know Rust to some extent, but if you do, those little condensed explanations and visuals might be beneficial to the understanding of the whole picture!
    Thanks for these series, Jon! You should consider doing more visual explanations, whether by hand-drawings (as you rarely do on live coding streams) or by using cheats.rs!

  • @Krzysztow1985
    @Krzysztow1985 3 года назад +2

    Man, I wish I had your skill of explaining things. You're awesome! Of course, the amount of knowledge you have is helping here, but it's a skill on its own.

  • @nathanielwoodbury2692
    @nathanielwoodbury2692 3 года назад +1

    Wow. This video was so incredible helping me understand rust deeper. Getting to understand on a more complex level and pushing my knowledge. Thank you so much for this video. I am so grateful for this.

  • @anssietelaniemi3397
    @anssietelaniemi3397 3 года назад +2

    Really Great content. Opening up the internals explaining how things works under the hood. The missing pieces. And why I am hitting the head in the wall (compiler).

  • @markay7311
    @markay7311 Год назад

    thank you so so much for these streams! I'm very interested in rust internals and I often come to your streams for clarification of complex stuff. really much appreciated

  • @Zizaco
    @Zizaco 3 года назад

    Great video. You gracefully explained what's behind the dyn keyword

  • @qm3ster
    @qm3ster 3 года назад +2

    I feel like at 1:05:26 you should have also implemented HeiAsRef:
    pub trait HeiAsRef: Hei + AsRef {}
    impl HeiAsRef for T {}

    • @jonhoo
      @jonhoo  3 года назад +3

      Yeah, in practice you'd want that blanket implementation too, but it wasn't really relevant to the discussion around vtables :)

  • @Codeaholic1
    @Codeaholic1 3 года назад +4

    I love your intro animation.

  • @antoniocorbibellot6532
    @antoniocorbibellot6532 3 года назад

    Thanks Jon for this enlightening video! Pure Gold.
    In case someone wants to see in action handcrafted vtables in C-land he/she can have a look at the headers from the Gtk toolkit or even have a look at the C-code output that the vala language compiler produces.

    • @Knirin
      @Knirin 2 года назад

      This video and ruclips.net/video/1-_EBEr0fxI/видео.html which goes over GObject have been very handy for a project of my own.

  • @KohuGaly
    @KohuGaly 3 года назад +6

    I wish you have covered the Any trait. It seems like it's super relevant to this topic.

    • @jonhoo
      @jonhoo  3 года назад +1

      There really isn't much magic to Any. It's just a method that returns a unique type identifier that then allows safe downcasting as I mention at the end :)

    • @KohuGaly
      @KohuGaly 3 года назад +2

      @@jonhoo I feel like "Can I downcast trait object back to original type?" is a fairly important question when discussing dynamic dispatch. And "Any" trait seems to be the idiomatic way to do it.

    • @jonhoo
      @jonhoo  3 года назад +2

      @@KohuGaly Ah, so, the answer is that you can only do it *if* your trait object includes the Any trait. You can't use Any to downcast an arbitrary trait object.

    • @KohuGaly
      @KohuGaly 3 года назад

      @@jonhoo So basically, the Any trait is optional... as per "don't pay for what you don't use" principle...

    • @jonhoo
      @jonhoo  3 года назад +1

      @@KohuGaly Yeah, you can think of it that way!

  • @mithradates
    @mithradates 3 года назад

    One day implementing that compiler error at 1:06:05 sounds awesome!

  • @TheZethera
    @TheZethera 3 года назад +7

    Thicc pointer

  • @pcfreak1992
    @pcfreak1992 3 года назад +8

    I love these streams! Please keep them up!

  • @johanngambolputty5351
    @johanngambolputty5351 Год назад +1

    Missed opportunity for
    ```
    match vial_broken {
    true => Box::new(DeadCat::new()),
    false => Box::new(AliveCat::new())
    }
    ```
    but Schrodinger hai is good too ;)

  • @-sbin
    @-sbin Год назад

    I'm reading your book and decided to look up a video on this concept to understand more... and guess who I find.

  • @insomniaccoder806
    @insomniaccoder806 2 года назад

    please please.. sir , if u can cover unsafe rust , it would be a great help for the community , but after all iam so glad u prepare this content for us ! tq so much 😃

  • @CyborusYT
    @CyborusYT 3 года назад

    3:04 "Let's get rid of this test, we don't need no test" Famous last words!

  • @johnnyegel
    @johnnyegel 3 года назад

    I just have to comment that this is a brilliant video if you are interested in Rust on a slightly deeper level. Kanonbra! :-D

  • @VivekYadav-ds8oz
    @VivekYadav-ds8oz Год назад +2

    Isn't a vtable generated for each _type_ , not instance? What is the problem then in inserting a static method inside the vtable? Every other method takes atlest one parameter, but I don't see how not taking a parameter is problematic.

  • @hniksic
    @hniksic 3 года назад +4

    At 1:41:05, should the drop function to accept `v: Box`? In the code as written, `v` is just a reference, so the compiler can't run `Drop::drop()` when it goes out of scope, since its owner might still be using it.

    • @xrafter
      @xrafter 3 года назад

      Same question

  • @michaelnajera7958
    @michaelnajera7958 3 года назад +3

    Making me a better swift programmer, thanks. But now you got me curious, how does swift handle dynamic linking of generics?

    • @jonhoo
      @jonhoo  3 года назад +4

      gankra.github.io/blah/swift-abi/ has all the gory details!

    • @michaelnajera7958
      @michaelnajera7958 3 года назад

      @@jonhoo Thanks!

  • @kiffeeify
    @kiffeeify 3 года назад

    @1:05:40"HeiAsRef". I wonder who that Ref guy is and why he is so hei ;-)
    Awesome video!

  • @VivekYadav-ds8oz
    @VivekYadav-ds8oz Год назад +1

    Also you said that we can only include "+ " in our variable signature if some_trait is an auto-trait, because auto-traits have no functions. But isn't Any also an auto-trait? It surely has functions, and which have different implementations for each concrete type. Now I'm not really sure how that comes into play.

    • @jonhoo
      @jonhoo  Год назад +1

      No, Any isn't an auto-trait. It has a blanket implementation (impl Any for T), but that's not the same. An auto-trait is one whose impls are generated by the compiler directly based on the structure of the type, and they never have any methods, which is not the case for Any.

  • @sodiboo
    @sodiboo 2 года назад +2

    15:33 Technically not entirely true. "Dynamic Libraries" is a broad term, and if you include for example, Windows' Dynamic Link Libraries, those can also contain .NET managed code. Those contain generic functions and types, and it is up to the runtime to "monomorphize" them just in time. But yeah, this is likely not what that question meant, since the context is dynamically linked *native* code

  • @random6434
    @random6434 3 года назад +2

    I disagree with the implementations at 7:34. I think they should still be `s.as_ref().len()` because you should be able to call it with any `T: AsRef`, even if T did not have a `.len()`. The optimizer might then see that for `&str`, `as_ref` does nothing and remove it. Having just `s.len()` makes it seem like there is something magical between `AsRef` and generics, which I don't think there is.

  • @alliu6757
    @alliu6757 3 года назад +1

    Thank you for your videos. Could you do a video about epoll and io_uring for file I/O?

  • @HyperFocusMarshmallow
    @HyperFocusMarshmallow Год назад

    I’ve been doing a bunch of minor projects in rust and I haven’t even ran into a use case where I’ve needed to use “dyn”.
    In other languages I’ve used the pattern a lot and maybe it’s just that I’ve worked on a different class of problems than I did in those languages.
    But I’ve found that I can often get away with using some different pattern in rust.
    There definitely are use cases where it’s needed, or at least very useful. But where I in some languages would make an interface and put a bunch of generic objects implementing that interface, often I find it more clear to define an enum with variants holding types.
    That limits how generic the code is. By quite a lot actually.
    It only allows the possible values I explicitly put in there. But quite often I don’t want to be generic over any object that happens to implement a trait. I just want to be very restrictively generic to exactly 2 or 3 different things that I implement myself.
    I’ll probably run into it more when I ramp up complexity a bit.
    That’s why I’m eating the video.
    But still. We don’t have to be maximally generic for everything we write, just generic enough to make writing the code convenient.

    • @KohuGaly
      @KohuGaly Год назад +1

      To paraphrase Dijkstra, "purpose of abstraction is not to be vague, but to be precise". A good support for abstraction lets you state precisely what you mean, without forcing you to be more vague or more specific than you want to be.
      Languages that have interfaces (traits) but no sum-types (enums) force you to over-generalize and therefore force vagueness. They push you to express closed sets of types (enums) as open sets of types (interfaces), even when you actually want a closed set (which is most of the time, actually, as you correctly point out).
      The main use case for traits and generics is when you want to provide new functionality to types that you have no control over (ie. when you write a library). Or you you have control over those types, but you want to keep it separated to reduce complexity.

  • @timanderson5717
    @timanderson5717 3 года назад

    can't the generic method thing be solved by more dynamic dispatch? I.e. The vtable for Extend has extend?

  • @marcorossetti4484
    @marcorossetti4484 3 года назад

    Thank you so much Jon! Very helpful!

  • @enbytiousmusic
    @enbytiousmusic 3 года назад

    Thank you! Very good Video! Keep it up! Greetings from Germany 👋

  • @willemvanderveen7567
    @willemvanderveen7567 3 года назад

    Thank you so much, this is such good content man much appreciated.

  • @RiwenX
    @RiwenX 2 года назад

    This was super informative, cheers!

  • @ryanleemartin7758
    @ryanleemartin7758 3 года назад +1

    I have my own MIT professor as a Rust mentor for free. Well, don't we live in exciting times!

  • @AllTheFishAreDead
    @AllTheFishAreDead 3 года назад

    Hey, great video - I have a noobie qn. Early on you discuss how in the trait object case you need the function argument to be sized so you can make a collection of them where each thing, the pointer type, is of the same size. However later on you say we can have a trait not add a static method to the vtable by requiring Self be sized, saying that the trait, dyn Hei, has no size. But didn't we pass a reference so that it was sized? Thanks!

    • @xrafter
      @xrafter 3 года назад +1

      Reference is sized not the object

  • @juchemz
    @juchemz Год назад

    1:29:25 I still don't understand why it's not possible to monomorphize the vtables. We compile the standard library at the same time as the rest of our code, so it should be possible to know the size of the vtable for a type+trait after monomorphization, even if it is large, and use that everywhere in our program. My vtables will be differently sized than yours, but that's just a different flavor of the same issue preventing us from having dynamic libraries.

    • @juchemz
      @juchemz Год назад

      Listening to your explanation again, I think my mistake is that we don't actually compile the standard library at the same time, we compile one crate at a time and just have access to the source for other crates. So for a normal generic function, if we introduce a use that std doesn't have, it would get compiled along with our crate, not std

  • @TomasSandven
    @TomasSandven 2 года назад

    Holy shit you’re Norwegian!? Your English is amazing.
    Hilsen fra Molde :)

  • @samighasemi3333
    @samighasemi3333 3 года назад

    Thank you for this video

  • @blablaqwertyful
    @blablaqwertyful 2 года назад

    It's tempting to say that type erasure causes all trait-related problems. Is it required that much to generate an efficient code? Why can't we preserve types?

  • @amaraojiji
    @amaraojiji 3 года назад

    Thank you a lot! I love those!

  • @joaodiasconde
    @joaodiasconde 3 года назад

    Great content. Like always!

  • @hmmmyessssssss7270
    @hmmmyessssssss7270 Год назад

    44:30 "you can keep using box after the stack frame of the caller has gone away", how is this situation possible? Won't the caller return only after this function has returned?

  • @tdwebste
    @tdwebste 3 года назад

    Document describing your vim setup.
    Please :)

  • @keent
    @keent Год назад

    does anyone know what theme is he using? looks pretty neat
    edit: looks like gruvbox or something

  • @老夏-u1q
    @老夏-u1q 3 года назад

    good tutorial, respect

  • @ivanzvonimirhorvat9744
    @ivanzvonimirhorvat9744 3 года назад +2

    IMHO It would be nice if you showed (traits) fat pointer representation with the debugger

  • @32zim32
    @32zim32 3 года назад +1

    s::weird is no possible because s doesn not name a type
    As you said type erasure occurs and the only thing you have is pointer to data and pointer to methods table
    Compiler does not need to know s type to call needed method
    I think the main reason is because in machine code level calling method through indirection is compiled into some stuff, which requires pointer to data to be available at this point. That's the main goal of dynamic dispatch and polymorphism.
    Method without self parameter can only be invoked through concrete type, which make no sense to include it in vtable which is needed only for magic like calling method without knowing type of object this method is called on

  • @kushagragupta7051
    @kushagragupta7051 3 года назад

    at around 1:05:52 when you talked about the multiple trait vtable, you said to create a new trait that requires the needed traits and use that. It would give a bigger vtable but it would still be 1 pointer right? And it would lead to code duplication as either the compiler would copy the trait implementations to another location or it would copy the function labels and call the original implementation methods. Wouldn't that be inefficient? Is there a way to say that I do want to generate a 3 pointer wide or even wider (based on number of traits) argument? with each pointer pointing to one traits vtable?

    • @ekrem_dincel
      @ekrem_dincel 3 года назад +2

      You can already do what you describe yourself by using custom vtables but trait objects don't work like that.
      And compiler only copies vtables, which usually has the size of (pointer_size * method_count). Basically it is a very very little overhead.

  • @elgusanito6991
    @elgusanito6991 3 года назад +32

    Who is the guy who disliked the video?? Let's locate him and sacrifice his soul for the sake of nightly rust.

    • @xrafter
      @xrafter 3 года назад +2

      @@JohnWalton_NET
      .Its going out of hand , now there are six of them

    • @araz911
      @araz911 2 месяца назад +1

      sorry, but I accidentally read guy asgay 😂 but anyways, nice vide

    • @araz911
      @araz911 2 месяца назад

      o

  • @antonioquintero-felizzola5334
    @antonioquintero-felizzola5334 3 года назад

    Hey Joh, what's the font you use in your terminal?

  • @thepuzzlemaker2159
    @thepuzzlemaker2159 3 года назад

    Thanks!

  • @jawad9757
    @jawad9757 2 года назад

    What font do you use?

  • @parthikpatel6108
    @parthikpatel6108 3 года назад

    How do you get your navigation bar/tabs on the bottom? Is that a firefox extension?

  • @OkamioftheRinnegan
    @OkamioftheRinnegan 3 года назад

    Why does an unsized type have to be the last field in a struct if the compiler is allowed to reorder fields anyway?

    • @KohuGaly
      @KohuGaly 3 года назад

      Because fields of struct are accessed as pointer offsets. For sized types, compiler may choose to reorder them, but compiler still knows where each field is located relative to the head of the struct.
      That does not work for unsized types. Because compiler can't know its size, then it can't access fields after it as offsets, because it can't figure out how big the offset should be. The only place where you (and the compiler) can put it is at the end of the struct.

  • @qm3ster
    @qm3ster 3 года назад

    in `struct Foo {f: bool, t: [u8], x: bool}` why can't the offset of `x` be determined by `len-sizeof x`?
    (such a struct combined with a #[repr] would be good for some zero-copy network encoding stuff)

    • @jonhoo
      @jonhoo  3 года назад +2

      In general the compiler expects field offset to be constant. You could imagine extending it to be dynamic, but that's a big language feature in and of itself.

  • @mariuskriegerowski8378
    @mariuskriegerowski8378 Год назад

    This is clearly an outlier: Usually I watch tutorials on youtube at playback speed = 1.5 (+- 0.25) because of relatively low information density. But crust of rust is often < 1.0. Thick (high quality) material to digest.

  • @softwarelivre2389
    @softwarelivre2389 3 года назад

    25:50 so we want something similar to Duck Typing in Typescript? Interesting

  • @jeffg4686
    @jeffg4686 3 года назад

    Where is Norwegia?

    • @jeffg4686
      @jeffg4686 2 года назад

      @Leon Tepe - yeah, i know. I always just think it sounds funny

  • @mmghannam
    @mmghannam Год назад

    Thanks!