Rust Experiment Failed - Static Dispatch IS Hard | Prime Reacts

แชร์
ฝัง
  • เผยแพร่เมื่อ 20 พ.ย. 2024

ความคิดเห็น • 197

  • @Buzzec9101
    @Buzzec9101 ปีที่แล้ว +163

    The issue with massive where clauses can be solved with traits and associated types. All the generics that are in the where clause on the struct can be put into a trait with all the required super traits. This makes you have only a single generic in your where clauses. DRYS

    • @krpp
      @krpp ปีที่แล้ว +23

      Yeah, had a little WTF moment when he mentioned having like 34 copies of it across different files

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

      Just came to say this, but it seems I don't have to. Traits can still be a mess, especially when mixed with lifetimes.

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

      had this exact same thought

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

      Yeah wanted to say this too

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

      There's a lot of places you can't do that yet, e.g. inherent associated types

  • @trashcan3958
    @trashcan3958 ปีที่แล้ว +26

    I don't get the obsession with OCaml. It doesn't really solve any of these issues. It just forces you to write your program in a different way. The author decided to use static dispatch for the performance benefits. However, rust with dynamic dispatch would still be much faster than OCaml.
    Also, the biggest issue that the author made was assuming that static dispatch would improve performance. Generally, this is true, but depending on the specific use case the improvements could be negligible.
    Using Arc is ok. Using Clone is ok. Using dyn is ok. Never optimize before profiling.

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

      Yeah trying to overoptimize is a mistake people seem to make a lot. I mean, this thing is doing IO with a database, it's not some game engine trying to get more frames. The cost of making it a dynamic dispatch is going to be negligible. Chasing 100% optimization is rarely worth it.

  • @razielhamalakh9813
    @razielhamalakh9813 ปีที่แล้ว +135

    This is where you use a tag trait specifically so you don't have to repeat the million where clauses every time. Skill issue.

    • @nevokrien95
      @nevokrien95 ปีที่แล้ว +14

      I was thinking God isn't there a macro or something

    • @jesustyronechrist2330
      @jesustyronechrist2330 ปีที่แล้ว +19

      @@nevokrien95 God should create a macro for it.

    • @guguludugulu
      @guguludugulu ปีที่แล้ว +2

      What's a tag trait? Google doesn't show anything but the docs for traits

    • @xvxvxvxv7704
      @xvxvxvxv7704 ปีที่แล้ว +11

      ​@@guguluduguluit's a trait that acts as a tag. You define an essentially empty trait that requires all those constraints then you constrain by requiring things to have this trait implemented.

    • @razielhamalakh9813
      @razielhamalakh9813 ปีที่แล้ว +11

      @@guguludugulu xvxvxvxv is correct, I just mean a trait that serves as a tag. It has no methods, a bunch of trait bounds, and has a blanket impl for the types with those trait bounds. In that way, requiring that trait in a trait bound will automatically imply all those other trait bounds for free.

  • @AndrewBrownK
    @AndrewBrownK ปีที่แล้ว +30

    ....I'm afraid to say I've wrangled much worse in Rust. There is a lot you can do to compose traits and fold away the complexity. Composition is the correct tool to fold up complexity, assuming you can factor things correctly.

  • @varshneydevansh
    @varshneydevansh ปีที่แล้ว +74

    Dude releases videos faster than Netflix series.

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

      that not hard, as we get a new show 2 times per year, in my country

  • @maninalift
    @maninalift ปีที่แล้ว +27

    I don't know rust, but I'm pretty sure there is a way to not repeat all those traits bounds. Like define one trait that depends on all the rest, or use a type alias.

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

      Anyone who knows Rust better than OP or I able to confirm? Really curious.

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

      ​@@Xevion really easy.
      The syntax `trait Foo = Send + Sync + 'static;` is nightly, but you can do
      trait Foo: Send + Sync + 'static {}trait Foo: Send + Sync + 'static {}
      impl

  • @quettle
    @quettle ปีที่แล้ว +24

    wouldn't something like a helper trait clear a lot of the noise? in the like of
    trait C: A + B + Clone + Send +Sync+ 'static{}
    impl C for T where T: A + B + Clone + Send +Sync+ 'static {}
    then it is just
    fn foo(x: impl C)

    • @AndrewBrownK
      @AndrewBrownK ปีที่แล้ว +2

      exactly

    • @AK-vx4dy
      @AK-vx4dy ปีที่แล้ว

      @@AndrewBrownK It is called supertraits .....

  • @belst_
    @belst_ ปีที่แล้ว +33

    doesn't the first #[async_trait] introduce dynamic dispatch instantly again, making this whole thing kinda moot?

  • @4445hassan
    @4445hassan ปีที่แล้ว +12

    Solving this is actually quite simple. Define a trait `IsDriver` implement it for driver if and only if all the where clauses hold. Use `where Driver: IsDriver`. That makes it a lot better and it's not that odd of an idea i think.

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

      you can constrain traits to methods too. hashmap does this

  • @porky1118
    @porky1118 ปีที่แล้ว +14

    8:00 There are things you could do to avoid this.
    1. Define trains for all of these lines, which are automatically implemented on everything
    2. Make a trait ("Traits") to include all these traits (trait Trais { type A: AbusePolicy + Clone + ...; type C: Clock + Clone ...; ... })
    3. type SimpleDriver = Driver;

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

      Thank you. It's so obvious, but I had not thought about doing it this way.

  • @SvetlinTotev
    @SvetlinTotev ปีที่แล้ว +17

    Just have a named thing that represents the repeating stuff.
    It's the general solution to avoiding repetitions. People figured that out more than 10000 years ago. And most languages allow you to name most things.
    In this case Rust does have a way of naming this mess by creating a trait to contain the generic vomit. So the API is only exposing an object with a trait for that object. Even if you end up chaining many APIs, at the highest level you would still end up with a small number of traits that contain all the messy stuff inside them. But that applies to everything else as well. You write a single word to call a function that may contain millions of lines of code. You use a single word to create an instance of a class that may contain millions of members in the tree of objects it contains. But you don't care about what's inside. You just care about the interface.

    •  ปีที่แล้ว +1

      Exactly. Although nothing prevents you to go crazy spreading the generic vomit all over the place. It does not mean that you have to. A trait per generic vomit could be an option here.

  • @remrevo3944
    @remrevo3944 ปีที่แล้ว +25

    8:50 Yes, this is ugly and I would love it when Rust trait bounds would propagate automatically, but until that is implemented it is actually possible to use a mix of super traits and generic trait implementation to basically define trait aliase.
    That way the bounds wouldn't have to be copied and changes would be much easier to do.
    So yes it is ugly and it would be nice if Rust had better support for these cases. But there are solutions!

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

      What about macros? The pattern itself seems simple enough that you would only need a few parameters for the identifiers. Or am I missing something

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

      ​@@harrytsang1501 Normal macros-by-example don't really work with trait bounds.
      At least not well.
      There is just no token to express trait bounds.

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

      You can just use a trait tag to avoid all of that copying.

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

    in c++ there's a dirty trick to 'solve' the template constraint thing: make an abstract interface and then check if the type you require derives from that interface. It doesn't have to make virtual calls, since you use the derived type as is, and it's sort of simple to migrate from dynamic dispatch to static. And since you can combine interfaces, checking if your type corresponds with the exact behavior you need is trivial: *template requires std::derived_from*, or even *template*

    • @ThePrimeTimeagen
      @ThePrimeTimeagen  ปีที่แล้ว +5

      i see elden ring, i like comment (even if i didn't read it)

  • @christopher8641
    @christopher8641 ปีที่แล้ว +6

    struct definitions should (almost) NEVER contain bounds on generics. Trait bounds define behavior, where a struct is a definition of memory layout. The moment you put a bound on a struct... you are obligated to include it on every impl block. impls define behaviors, not layout. Behaviors are defined by their bounds. I say "almost" because some marker traits (I believe just "Sized") makes sense to include on a struct, because Size is closely related to layout rather than behavior. Somewhere there is a github issue of David Tolnay arguing to include a lint in clippy for this exact thing. And tbh, that lint would have saved me soooo much time when first learning rust.

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

      You might need bounds for the contents of your struct to even be defined. Something like
      struct Foo {
      bar: I::Item,
      }

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

    I see a lot of people saying "you can simplify it with a supertrait that combines all the others"... There's yet another solution too, why not just put all the possible drivers in an enum? Sure, there'll be one extra branch compared to the completely template solution, but:
    * it's easily extensible
    * you can use a crate (I forget the name but I know it exists) to automatically implement a trait for an enum where all the variants implement the trait too, so you can just use it like a driver with no source code changes
    * if driver doesn't change at runtime, all the branches will be predicted anyway, the overhead will be minimal
    And you can wrap up all the trait bounds required just at the enum definition!

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

      This is the comment I was looking for! "Dynamic" dispatch doesn't have to be a magic abstraction like a trait object, you can just make a mini abstraction to solve your usecase without losing most of the benefits of not using runtime type objects.

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

    I interface with a large corporation that implemented their services in Go, using Rust on my end. I can say that the holes in their Go implementation are glaring. Don't use Go for an REST API type thing. There are all kinds of logic errors that Rust would've prevented

  • @RenderingUser
    @RenderingUser ปีที่แล้ว +18

    apparently, this is just a skill issue

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

      its so interesting to me that people think "I want this complex ass thing to be perfect at compile time" and then do 1) the most naive solution possible, 2) spend no time making it better, then 3) revert everything and praise the original design. Happy for the developer that their codebase is better, but seems like they didn't even know what they wanted. Nonetheless, playing with rust types is fun so I don't blame the naive/intuitive refactoring approach.

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

    I'd argue that sharing a transaction is just hard regardless of the language. Especially when it involves some kind of distributed commit bollocks that i'm sure works fine except when it doesn't (which, spoiler alert, is exactly the cases where you care about it in my experience). In the end, having to use multiple transactions in a code base (or module depending on your architectural bent) seems like a huge smell to me. Having said that just like all code smells, that doesn't mean it's not actually necessary.
    Also, I haven't dug around the III-IV code enough but I wonder how much of this is just down to things being included that shouldn't be the database driver's problem. Not that i'm ragging on the guy if that is the issue... keeping a design clean like that is a herculean task. Also, i'd probably set the general rule to be using dynamic dispatch and save static dispatch for places where it really matters which i'd argue it generally doesn't if your context is Web API endpoints talking to a database. You'll spend longer on protocol management and Db IO than you ever will on dynamic dispatch. (which is pretty much what you said)

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

    In server code to avoid lifetimes just wrap your stuff in Arc. Or any other smart pointer of your choice. In IO bound context like web it would not matter and you have no silly lifetimes.

  • @aftalavera
    @aftalavera ปีที่แล้ว +2

    Prime is saying the same shit about the camel, previously said about rust! He is just a JavaScript technician that works for Netfix!

  • @sub-harmonik
    @sub-harmonik ปีที่แล้ว +10

    I have no experience with rust, but could you not have an interface (or 'trait'?) that was declared to extend those other traits? seems like you could and just declare that trait instead of having to list every trait it 'extends' in every function that uses it. Even if it's a generic. I don't get it

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

      That would be the JEE way of doing it and everyone knows thats bad. Especially people who dont write JEE... :p

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

      100% true

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

    18:30 successful inlining increases execution speed at the expense of a larger binary. Respectfully, the author of the article got it backwards.

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

      Often inlining will be for a single use, which results in sightly less overall code (a few bytes for the call and function prologue), and the real value is when the inlining lets the optimizer take advantage of local conditions to simplify the inline code, so it's not always an increase in size.
      But you're generally correct!

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

    This isn't inherently an issue about static dispatch at all.
    However, doing static dispatch right AND ergonomic is pretty hard in some circumstances like this, and to have a truly ergonomic solution you need to either dive into the rustnomicon and carefully write some unsafe bits, AND/OR get to writing some macros.

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

      there is also a way to handle bits on a per method basis, thus you get less of the inconveniences

  • @conando025
    @conando025 ปีที่แล้ว +6

    Why not create new super Traits like `Trait A: Clone + Send + Sync {}` You would still have to specify it but surely writing where `B: A` is less atrocious. Am I missing a downside of such an approach?

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

      It could be an issue if functions do not share trait bounds aka function 1 needs traits A B C but function 2 needs A B D. Composition can still help, at the very least in the example code & what we can infer their codebase to look like with the clauses "repeated". A different issue (that probably isn't what the developer was facing) could be that you may want additional/different function-specific constraints per function for preventing misuse of the function, though in rust this is typically more of a stylistic choice than a need, since this prevention of code smell is better solved using the compiler as a way to get the naive solution and then using lints or reviewing your code to optimise later.

  • @krumbergify
    @krumbergify ปีที่แล้ว +6

    It’s the same with templates in C++. Using dynamic dispatch (virtual methods through interfaces) is often easier, cleaner and compiles faster even if it has a runtime cost. Don’t invoke a dynamic dispatch method to write a single byte, instead pass it a whole buffer and the vtbl-jump penalty becomes negligible.

    • @stevenperez5260
      @stevenperez5260 ปีที่แล้ว +2

      Totally agree, this issue is more related to bad code design rather than Rust limitations

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

      Yes, it is bigger not smaller (but faster in runtime). However in C++ you can use an interface (just for the type, no virtual methods) and then set a requirement in the derived template. All static checked and super easy to implement with respect to Rust.

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

    I have seen in the comments way to massively simplify the issue, but rust is also working on implied trait bounds which would eliminate the need for most where clauses in this code

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

      yeah Rust could really use some more inference tools where you can just type a keyword and just tell the compiler to figure it out. Even if it was just a relative type definition, that would be good. Like "typeof Argument1(f)" that way if you ever changed the type of f's argument, it would propagate.

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

    My biggest problem with Go is the error handling. If it had pattern matching like Rust I'd probably use it more.
    Due to your shilling, I'm going to have to check out OCaml.

  • @4445hassan
    @4445hassan ปีที่แล้ว +3

    Also in most cases the correct answer would be to use an enum if what you are developing is not a library. Even if it is a library there is a real benefit to put all the variants you define yourself into an enum and having an `Other` variant which contains the `dyn`.

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

    That's why you don't pass the DI struct around directly; you define a trait, turn all the parameters into associated types, implement it, and then pass down an `impl FooContext`. This is symmetrical to how you'd define DI in C# or Java, only without dynamic dispatch.

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

    Its interesting how "lets see" is your "I'm speaking further than I've read, I need to go back to catch up"

  • @tehsimo
    @tehsimo ปีที่แล้ว +2

    That driver definition makes OO look good

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

      this is what OO would look like if it didn't have composition or types (aka not OO). The comparison doesn't work! I know you were probably joking, but I wanted to agree before thinking about it lol

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

      @@mikkelens yes I was joking

  • @KayOScode
    @KayOScode 9 หลายเดือนก่อน

    i use cpp if I need maximum performance, rust if I need high performance or I want to use rust, and c# if I don’t care about performance at all. But inevitably I always regret using c# because i want more performance later down the road

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

    Is there any world where the speedup from static dispatch to relational database calls is relevant when compared to the time spent in IO for those calls?
    Asking for a friend…

  • @GigachadRustacean-lu8bo
    @GigachadRustacean-lu8bo 4 หลายเดือนก่อน

    if you would go for the static dispatch , and utilize a bunch of super traits , it is better to create macro to avoid the disaster of having to write all implementations. If u wanted performance then let the compiler do the work for you… at the expense of longer compile times, but you can opt to expand those macro later on if u wanted to…

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

    Untyped null is now considered a billion dollar mistake, in the future type metaprogramming will also be considered a billion dollar mistake.

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

    Leaking the where block to the REST layer is the bigger problem.

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

    The feelings about rust have changed so much on this channel

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

      Prime is a pretty dramatic guy. He couldn't stop shilling Rust when it was new to him and now he can't stop shilling the new shiny thing he can't see negatively. Now that he's over Rust as the One True Language he can view it more realistically, but goes a bit further and views it negatively to contrast it with his feelings for other languages. To me what makes Rust shine through his perspective only is how much he has to admit it's still super good despite it maybe not being deity-status, contrasted with how he doesn't really talk about zig that much anymore since trying/"moving onto" OCaml

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

    Lol, I just did something similar this week resulting in 2x end-to-end speedup

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

    ...It's safe because it makes it impossible to try and do things that haven't already been done... the framework achieves UNLIMITED SAFETY despite being written entirely in gotos! It's perfect safety record is compounded by this decision as most developers refuse to even CONSIDER working on systems that use just one goto that's not next to a token called "while" or "void*". Arbitrary semantics implemented as macros are tolerated giving the framework infinite extensibility that's NEVER USED, further contributing to its overall safety.

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

    There are some good comments at the end of the reviewed article I think. Would be curious about your thoughts on those comments!

  • @ghosthaunting15
    @ghosthaunting15 ปีที่แล้ว +16

    Tom is genius

    • @thingsiplay
      @thingsiplay ปีที่แล้ว +2

      Tom is genius

    • @metaltyphoon
      @metaltyphoon ปีที่แล้ว +2

      Bruh… this is an overplayed joke already

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

      Isn't it: "Tom's a genius"?

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

    Ultimately it seems like the only reason they need to change the database is so that they can use sqlite in tests, apart from that, using just Postgresql is fine. I hate to be the TDD guy, but this is the issue with testing after writing the code, you can build something that is so tightly coupled to a system that shouldn't be in tests that it turns into this when you actually get around to testing.
    If this was built up with tests using sqlite and units using postgresql, piece by piece, it could have built up a must less leaky abstraction. It still could have become this, but the issues would have shown up sooner where it would have been easier to fix.

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

    I wrote something like this like 2 weeks ago but ended up refactoring it just fine.
    But I do agree there's no clear way to refactor the number of generics in a thing both up and down in rust. That's super annoying and I hope something like trait bound alias can land.
    Before that some kind of macro can probably help in some situations.

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

      What do you mean by "trait bound alias"? Like the "type" keyword? I guess you can't use type for traits like you can for structs/enums (since they aren't types in the same way), but you can use trait constraints to bundle them together, and it feels pretty similar: "trait C: A + B { }"

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

    Once put two days of work into setting up icinga... took me a day to get it running stable in docker (first time)... then i saw the configuration and dropped it almost instantly xD
    Sunken cost fallacy my ass :)

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

    Isn't that where associated types come in!?

  • @isodoubIet
    @isodoubIet ปีที่แล้ว +5

    Just rewrite it in C++ lol

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

    If you are trying to make something this complex, sharing transactions, extended traits used on several layers... Static dispatch is simply not the right choice. Don't make it sound like static dispatch its the only right way. Dynamic dispatch is actually the most common way how every other language does this. It is perfectly fine. Rust just gives you the rare option to create a static source from generic functions in case it is possible.

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

    That absolutes line is an absolute

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

    Tom would've figured that shit out! Did u know that Tom is a genius?

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

    6:09 Is there no form of type aliasing in Rust?

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

    You missed the obvious: That phrase is an absolute. Ergo, anyone using is outing themself as a Sith.

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

    22:08 Raw JS is super useful!!

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

    The way he talks is Bill Burresque

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

    “I tried a day of java and java sucks but javascript is great”. That hurts to hear even as a strawman.

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

    Massive skill issue.
    the syntax `trait Foo = Send + Sync + 'static;` is nightly, but you can do
    trait Foo: Send + Sync + 'static {}trait Foo: Send + Sync + 'static {}
    impl DbDriver for T {}
    trait TxDriver: Tx + Send + Sync + 'static {}
    impl

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

    As a JS developer (primarily), yes, it does suck!

  • @headlibrarian1996
    @headlibrarian1996 4 หลายเดือนก่อน

    Not sure why the author thinks modern C++ is deranged but this is not. Rust is usually great, but I’ve never had to write monstrosities like that in C++.

  • @-ion
    @-ion ปีที่แล้ว

    8:51 Simply fix the ™ sign in the browser's developer tools, problem solved.

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

    > `Arc`
    Am I the only one who uses feature flags and conditional compilation to do mocking in Rust? I detest having to change the way my code is written just to accommodate mocks

  • @0xCAFEF00D
    @0xCAFEF00D ปีที่แล้ว

    5:50
    Not familiar with Rust but this kind of repetition could easily be solved with a C Macro :)

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

      trait composition (written like "trait C: A + C { }") is like trait 101 and its pretty interesting that the author doesn't mention it or isn't familiar with it

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

    What if I am also a child?
    Only a sith deals in in absolutes.

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

    This is the worst thing about Rust in my experience, its a leaky language, in the sense that implementation details of your types and modules easily explode into a mess across the entire program.

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

    big skill issue right there, use associated types

    • @ThePrimeTimeagen
      @ThePrimeTimeagen  ปีที่แล้ว +2

      you can also constrain the method to the trait required like hashmap does (you don't need a bunch of traits to define all its behavior, just on the methods you use)

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

      @@ThePrimeTimeagen Very good point! Though that being said, if your trait has a method that takes a generic parameter, it won't be considered object-safe anymore (so, no Arc).
      I'd rather prefer something like this:
      trait Foo {}
      trait Bar {}
      trait Baz {}
      trait Qux {}
      trait DoesItAll: Foo + Bar + Baz + Qux {}
      impl DoesItAll for T where T: Foo + Bar + Baz + Qux {}
      Then you can just do a "where T: DoesItAll" on your generics and boom, you've reduced the where-clause-boilerploooting.
      Rust does actually provide a lot of ways to reduce complexity, but unfortunately those are hard to come by when you've already coded yourself into a corner.

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

      ​​​@@azratosh
      Your method is good and it has its place, for example when you do have unsafe code and you need to uphold some invariants no matter what. But for that use case it might be an overkill.
      About the type safety of constraining methods to traits. Rust will not let you exhibit behavior (call a method) if traits are not satisfied (for example, call `.clone()` if trait is not `Clone`, so it is absolutely type safe to, for example, have a struct that should be `Clone` but to not restrict it's generic bounds at the definition points, but rather implement `Clone` where all generics are `Clone`. Then, at the point where you need it to be `Clone`, constrain. That will save a lot of boilerplate.

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

      @@ddystopia8091 Oh yeah, totally. I would never constrain the T on a Struct directly (unless really necessary); only on the impl blocks. Keeps everything tidy and modular.

  • @АнтонФамолия
    @АнтонФамолия ปีที่แล้ว

    Why even optimize dynamic dispatch when you are doing network call with it

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

    Python rewrite, it'll take you 10 minutes and there's no compilation. Let's go!

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

    Are you alright Prime my dude?
    You look a bit tired in the video.
    Are you taking proper time to rest?

    • @ThePrimeTimeagen
      @ThePrimeTimeagen  ปีที่แล้ว +6

      i am ! i have reduced my streaming 1 day less a week.
      the thing that is hurting me right now is teaching courses for front end masters

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

    Make a playlist for prime reacts

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

      ...?
      look at the playlist this is on!!! its on prime reacts!

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

      ​@@ThePrimeTimeagenanotha one

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

    Couldn't the duplication not handled with a Macro?

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

      25:19 apparently not

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

      @@bary450 Oops, not sure how I missed that part. Thanks for pointing it out.

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

    D's openmethods = problem solved 😎

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

    Forth. Thanks for the recommendationt to practing coding typing! super helpful!

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

    if you have to paste a assload of where statement 44 times why would you not include it in either a build script or a macro of some kind?

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

    `trait Db: Send + Sync {`

  • @AK-vx4dy
    @AK-vx4dy ปีที่แล้ว +1

    This article again?

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

    My hot take is there's no such thing as a zero cost abstraction

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

      The whole reason to use C++ is that it offers many zero-cost abstractions.

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

      I'll get you one better: there isn't anything that is universally true/perfect for everything, it's just a matter of tradeoff scale along with what tradeoffs you care about and what tradeoffs you don't.
      also @agcwall misunderstanding the original comment and acting like c++ is uniquely offering Perfect Zero-Cost Abstractions in this regard is pretty funny considering the subject matter

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

    I do appreciate rust on a personal level, I am not a rust shill, but please don't take this as a bad faith criticism. this is a genuine comment/question:
    I am relatively new to your channel, and you seem like someone who tries to see things in a logical way, but when it comes to rust, it seems like you want to see it fail. I'm curious to understand why that would be the case.

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

    There is a solution! Just a trait wrapper! Really!
    Example in my comment below (hope TH-cam didn't ghost-remove it)

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

      pub struct SimpleDriver {
      driver: X,
      }
      impl SimpleDriver {
      pub async fn simple_run(&self, cmd_params: CommandParams) -> Result {
      self.driver.handle(cmd_params).await
      }
      }

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

      // part2
      #[async_trait]
      pub trait DriverTrait {
      async fn handle(&self, cmd_params: CommandParams) -> Result;
      }
      #[async_trait]
      impl DriverTrait for Driver
      where
      F: Fn(CommandParams) -> T + Send + Sync + 'static,
      T: Future + Send + Sync + 'static,
      {
      async fn handle(&self, cmd_params: CommandParams) -> Result {
      let result = (self.inner)(cmd_params).await;
      result
      }
      }

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

    too much videos, quality is meeeh. Was nice to follow you for a time. You gave some good advice!

  • @Robert-zc8hr
    @Robert-zc8hr ปีที่แล้ว

    TBW, I still think code generation is the way.

    • @Robert-zc8hr
      @Robert-zc8hr ปีที่แล้ว

      But at compile step, where the generated code is the output of a library then then you import from somewhere else.

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

    My eyes

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

    OCaml shilling is NOT annoying.

  • @AK-vx4dy
    @AK-vx4dy ปีที่แล้ว

    @9:30 This where could be shorten and DRY-ed by supertraits...
    Guy don't know Rust well and trying to implement concepts from another languge.
    I saw the same with guy who was c++ programer and make presentation about how he tried to port his app to rust.
    When he wrote that sql driver spoils rest endpoints that was clear that design is poor and/or cargculted from other langage

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

    7:53, can't do macros for that?

  • @js-ny2ru
    @js-ny2ru ปีที่แล้ว +1

    You don't like Rust anymore Prime?

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

    this sounds like a case for a macro

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

    Elm is better than TypeScript it is a lot more ergonomic

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

    yes, All of us are :(

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

    twenty ninth?
    Edit: Fixed grammer errors

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

    So much time spent on Unreadable types when you could just manually write a codegen build step in less time. C doesn't have this problem

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

    Are there good lanugages with async/concurrency without red blue function distinctions? (other than go)

    • @RenderingUser
      @RenderingUser ปีที่แล้ว +2

      whats red blue function distinctions?

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

      @@RenderingUser JS and Rust have regular and async functions. You can call regular functions from async but not vice versa. Distinction with weird asymmetry.

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

      @@gritcrit4385 I see. But is that much of a problem tho?

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

      ​@@gritcrit4385you *can* call sync from async, but you need to be careful it won't block, and you *can* call async from sync, but not then get the result without higher level coordination.

    • @sub-harmonik
      @sub-harmonik ปีที่แล้ว +1

      I believe zig has that ability (when the async stuff is actually included in a release lol)
      coroutines in lua are made from normal functions w/ the ability to yield from any function in the coroutine (anywhere in the stack), not sure if that counts.

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

    Should have used a macro to automate that where block.

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

      Unneeded macro! Just do trait composition/self-constraints: "trait C: A + B { }"

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

    11:46 Just go back to dyn, not GC!

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

    This is one the issues I have with adding any constraint, it just infects every piece of code that the type/trait is involved with.

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

    Just make type aliases

  • @kwinso
    @kwinso ปีที่แล้ว +2

    NaN?

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

    Please more OcaML shilling

  • @justinliu7788
    @justinliu7788 ปีที่แล้ว +5

    Second?

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

    Красава супер видео

  • @DarksomeX-m3y
    @DarksomeX-m3y ปีที่แล้ว +3

    Stupid youtube bot deleted my comment because of a link
    Here's rust playground gist: 4ce0f67a1cc096b217dea252465059e3
    The point is that you can specify all you trait bounds in a single trait with associated types. And leaking abstractions is not a "Rust issue", it's a skill issue

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

    Child exploitation is wrong absolutely therefore I'm a sith and proud of it. The "dark side" of the force allows one to shine more brightly imo. Good vid PrimeTime. Ethical appeal 11/10.
    From the vid I see that setting up domains and policies are the real issue where Go and others are merely a way to develop (like DB transactional interfaces) without getting involved with policy definition which is a double edged sword; laziness being the edge facing the wielder. Ignorance regarding Rust policies is valid but understanding one's own code and policies regarding interfaces would make it far easier to query the community and documentation relationally, so...
    Not advocating for or against Rust and others but many arguments/bullets seem like a one and done throwing in of the towel many times regarding Rust development. Tech officers and testers are generally going at languages with a bit more openness and curiosity as well as a deeper understanding of things of such a magnitude require the adequate level of consideration opposed to a quick "deep dive" considering something as monumental as a total migration. Looking back it feels as though I'm regurgitating what you've stated and wonder if those "devs" are listening to your advice because you sound familiar to a CTO. Good stuff.

  • @randomperson6749
    @randomperson6749 ปีที่แล้ว +6

    First?