Crust of Rust: Dispatch and Fat Pointers

แชร์
ฝัง
  • เผยแพร่เมื่อ 20 พ.ย. 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.

  • @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!

  • @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!

  • @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.

  • @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!

  • @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.

  • @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.

  • @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

  • @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 :)

  • @Zizaco
    @Zizaco 3 ปีที่แล้ว

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

  • @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

  • @pcfreak1992
    @pcfreak1992 3 ปีที่แล้ว +8

    I love these streams! Please keep them up!

  • @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 th-cam.com/video/1-_EBEr0fxI/w-d-xo.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!

  • @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

  • @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.

  • @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 ;)

  • @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!

  • @Codeaholic1
    @Codeaholic1 3 ปีที่แล้ว +4

    I love your intro animation.

  • @CyborusYT
    @CyborusYT 3 ปีที่แล้ว

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

  • @mithradates
    @mithradates 3 ปีที่แล้ว

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

  • @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.

  • @timanderson5717
    @timanderson5717 3 ปีที่แล้ว

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

  • @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.

  • @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 😃

  • @-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.

  • @kiffeeify
    @kiffeeify 3 ปีที่แล้ว

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

  • @alliu6757
    @alliu6757 3 ปีที่แล้ว +1

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

  • @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

  • @marcorossetti4484
    @marcorossetti4484 3 ปีที่แล้ว

    Thank you so much Jon! Very helpful!

  • @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

  • @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?

  • @TheZethera
    @TheZethera 3 ปีที่แล้ว +7

    Thicc pointer

  • @willemvanderveen7567
    @willemvanderveen7567 3 ปีที่แล้ว

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

  • @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.

  • @RiwenX
    @RiwenX 2 ปีที่แล้ว

    This was super informative, cheers!

  • @enbytiousmusic
    @enbytiousmusic 3 ปีที่แล้ว

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

  • @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

  • @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?

  • @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

  • @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.

  • @keent
    @keent ปีที่แล้ว

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

  • @ryanleemartin7758
    @ryanleemartin7758 3 ปีที่แล้ว +1

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

  • @joaodiasconde
    @joaodiasconde 3 ปีที่แล้ว

    Great content. Like always!

  • @samighasemi3333
    @samighasemi3333 3 ปีที่แล้ว

    Thank you for this video

  • @amaraojiji
    @amaraojiji 3 ปีที่แล้ว

    Thank you a lot! I love those!

  • @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.

  • @tdwebste
    @tdwebste 3 ปีที่แล้ว

    Document describing your vim setup.
    Please :)

  • @TomasSandven
    @TomasSandven 2 ปีที่แล้ว

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

  • @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.

  • @老夏-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

  • @antonioquintero-felizzola5334
    @antonioquintero-felizzola5334 3 ปีที่แล้ว

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

  • @thepuzzlemaker2159
    @thepuzzlemaker2159 3 ปีที่แล้ว

    Thanks!

  • @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.

  • @parthikpatel6108
    @parthikpatel6108 3 ปีที่แล้ว

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

  • @jawad9757
    @jawad9757 2 ปีที่แล้ว

    What font do you use?

  • @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

  • @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!