The genius of Rust constructors

  Рет қаралды 43,717

Let's Get Rusty

Let's Get Rusty

Күн бұрын

Пікірлер: 247
@letsgetrusty
@letsgetrusty Ай бұрын
Get your *FREE Rust training* : letsgetrusty.com/bootcamp
@toast_on_toast1270
@toast_on_toast1270 Ай бұрын
C++ doesnt force you to do anything, and in my opinion, thats the problem. If you want a return value from the constructor, you can do it. First make a static member 'create' function returning your std::optional or whatever, put the failure-prone logic in this function and then copy/move whatever is needed into the constructor of your class. The compiler can decide to use NVRO so you dont have to worry about performance overhead. Then just make the constructor private so users know to use your builder instead. Many people do not think to use this trick, which brings me to the real problem with c++: that it *doesnt* force you to do things a particular way, leaving way for inconsistency, misuse of APIs, avoidable mistakes and bad design choices. So, I like that rust embraces a more prescriptive approach.
@letsgetrusty
@letsgetrusty Ай бұрын
Yes that's a great summary of the core issue!
@ciamej
@ciamej Ай бұрын
That’s the code pattern I always rely on, but it feels kind of unnatural in C++ forcing me to both create private constructors and public static ‘factory’ methods.
@toast_on_toast1270
@toast_on_toast1270 Ай бұрын
@@ciamej yeah, well almost everything in C++ is more than a little idiosyncratic. Its a language that has persisted through so many paradigms and movements in its continual development. It tries to offer everything, and always favors expressiveness over conciseness and ease of use. Consider this example function declaration: "[[nodiscard]] auto get_data() const noexcept -> std::span;". To most people, this is a nightmare (I even decided to spare you the 3x increase in verbosity from the added template stuff this code would often have). To me, it's beautiful, because it expresses exactly the intent behind the function, namely that it returns a view to some data, has no side effects, cannot throw an exception. But even I have to admit, a header file filled with so much visual clutter makes you wonder if there isn't a better way (perhaps by making these modifiers and attributes default, because they should be). It's weird because, at this point, correct usage of the language (imo - see Jason Turner's POV on this) necessitates subscribing to all of this ritual, a bit like joining a cult. It seems like Rust, more than anything, tries to make these modern considerations idiomatic, without having to support all of the idioms from the previous half century. I have yet to dive into it, but I'm hoping that Rust is the beautiful language C++ wants to be, but cant.
@c-antin
@c-antin Ай бұрын
Great video! One thing to add: you can initialize a struct partially by passing `..Default::default()` to the struct initialization.
@landonwork675
@landonwork675 Ай бұрын
This only works if your struct impls Default
@Mankepanke
@Mankepanke Ай бұрын
...which then must be able to initialize everything. So this is mostly sugar for creating a struct instance, then overwriting a field with a new value. (But the compiler can remove the redundancy) You still cannot create an uninitialized field outside of unsafe rust or by opting in to it with MaybeUninit.
@Spiker985Studios
@Spiker985Studios Ай бұрын
The nit-pick wasn't that you could create an uninitialized field, it was that you can create an object with only partial default values - not being limited to using the default implementation wholesale
@yondaime500
@yondaime500 Ай бұрын
The ".." syntax in this context just means "if any fields are not mentioned above, take them from this other fully initialized instance". Passing Default::default() is the most common use case, but you can actually put any expression that evaluates to an instance of that type.
@Mankepanke
@Mankepanke Ай бұрын
@@yondaime500 TIL. Thanks!
@OMGclueless
@OMGclueless Ай бұрын
Your example at 2:03 does in fact call the Employee override of introduce(). The Base implementation of introduce() can only be called _by the Base class constructor itself_. This is still sometimes confusing, you might expect that any Base class functions that are overridden are not callable at all, but it's not quite as alarming as your example suggests -- code in Example's constructor will always call Example's methods.
@enigma_dev
@enigma_dev Ай бұрын
Good catch. I think they meant to show the opposite. The Base class calling a virtual method in the constructor. (ie Person() calling Introduce();) In that case, the child virtual override will not be called, basically because child isn't constructed yet, while the base is being constructed.
@enigma_dev
@enigma_dev Ай бұрын
Made a compiler explorer example to show the problem of calling virtuals in base classes: /z/zsaTY73jY
@ХузинТимур
@ХузинТимур 27 күн бұрын
Yeah, vtable pointers are overwritten before calling a constructor. E.g. if we have classes Parent and Child, there would be such steps: 1. Write pointer to vtable of Parent to hidden pointer. 2. Execute Parent ctor. 3. Write pointer to vtable of Child to hidden pointer. 4. Execute Child ctor.
@proficiency03
@proficiency03 Ай бұрын
You can make a series of Rust projects. All the way smaller to more bigger and complex projects.
@MrCyanobacterium
@MrCyanobacterium Ай бұрын
The issues mentioned about C++ constructors are not an issue in Java or C# (except the part about throwing an exception), so these aren’t OOP problems but a C++ problems
@danilmiroshnikov6130
@danilmiroshnikov6130 Ай бұрын
this. idk why author really mention that. Anyway, it's obvious that any language would be any way possibly perfect in its core principles/scenarious like creating objects. Imo, the difference or what makes language a language is the whole API ecosystem. As a Java dev I can tell he one it has is about business features, which is nice for some things and bad for others. And the same goes to any other lang, including Rust.
@MrDavibu
@MrDavibu Ай бұрын
Exceptions have to be handled in Java, so it's the same as the match in Rust. Quite a lot of bad faith arguments in this video tbh.
@amynagtegaal6941
@amynagtegaal6941 Ай бұрын
I wasn't really aware of that C++ quirk explained in the beginning.. But now looking back at my code i see that i already thought about it unconsciously and implemented a work around... I guess i was already aware of this while not being aware of being aware of it???
@dampfwatze
@dampfwatze Ай бұрын
0:07 I love that he picked Dart as a well known language on his list! Dart is Fire!! 🎯🔥🔥
@davidowens9597
@davidowens9597 17 күн бұрын
I agree. I like Dart, Go, and of course, Rust.
@clementdato6328
@clementdato6328 Ай бұрын
One problem with this is upstream APIs will become constrained: all extra parameters are breaking changes to the downstream. There are thus new/builder patterns to mitigate this. This automatically forces library providers to boilerplate many of their types with such patterns to ensure further extensibility.
@jongeduard
@jongeduard Ай бұрын
Note that there are still better design practices possible in C++ too, by following a more rustacean approach. 🦀 From examples I what see people doing is using a single struct with multiple fields inside it, used as the only member of a surrounding class, and then initialize that as a whole from the class it's constructor behind the colon, so that it has to be created all at once. Because in that way C++ constructor syntax does actually enforce it. For additional work after construction the factory pattern 🏭 should be used, which is basically what new() methods in Rust are too. Avoid any work inside a C++ constructor body.
@carterthaxton
@carterthaxton Ай бұрын
The Rust naming convention for traits would be to call it “Introduce” instead of “Introduceable” (which should really be spelled “Introducible” anyway). At first it seemed foreign to me, but I’ve come to absolutely love this convention.
@EmranAhmed08
@EmranAhmed08 Ай бұрын
What editor do you use to move code block like 1:34-1:35 for tutorial?
@blt_r
@blt_r Ай бұрын
One downside of rusts approach is that new objects must be returned from functions, so they can only be constructed on stack. This is bad for big objects that you can't fit in the heap. You can make a constructor that returns a Box, but to create it with Box::new you will still have to pass the object by value through stack (with unstable box keyword it also isn't guarantied that the object will be directly constructed in heap and not copied there from stack). It's also commonly wanted to construct an object in already allocated place (like placement new, or vector::emplace_back in c++). Right now, this cant be done with safe rust, because it will necessarily involve passing a pointer to an uninitialized object.
@delir0
@delir0 Ай бұрын
I can't imagine a single real world case where it is a downside
@irrelevantgaymer6195
@irrelevantgaymer6195 Ай бұрын
Then write it in unsafe rust
@TheShynamo
@TheShynamo Ай бұрын
@@delir0 For example, when developping a video-game, you need a lot of performance because FPS is critical. Allocating memory is expensive, so the game engine pre-allocate a huge chunk of memory, and then lets you store and load objects within it without having to do a system call, which increases performance (FPS).
@anderdrache8504
@anderdrache8504 Ай бұрын
@@delir0 it overflows the stack when constructing large objects
@raykirushiroyshi2752
@raykirushiroyshi2752 Ай бұрын
​@@TheShynamo why write games in rust... You might as well use Odin if you don't wanna use c++. If you do want performant application,you will have to use unsafe rust
@v-sig2389
@v-sig2389 Ай бұрын
I'm not even an unconditionnal fan of c++, but the way you demolish its constructors makes me want to take its defense 😂
@Pritam252
@Pritam252 Ай бұрын
I like rust's approach to the problem, despite me trying to use workarounds for problems like I did in C/C++ and finding myself frustrated instead. 😂
@leftaroundabout
@leftaroundabout Ай бұрын
So, how is this unique and any more genius than how Haskell has done it since the 90s?
@pmmeurcatpics
@pmmeurcatpics Ай бұрын
The advantage of Rust is that it's actually being used. And I don't say this as an insult to Haskell, or FP in general - it's just a common problem that they, while being very nice theoretically, tend to feel very unapproachable for people without PhDs
@leftaroundabout
@leftaroundabout Ай бұрын
@@pmmeurcatpics that's the common argument, and it's a fair one (though Haskell and O'Caml are definitely not mere theory but fully capable languages). My complaint is that features are presented as unique accomplishments of Rust when in reality they have been a thing long before Rust came around and the mainstream just didn't pay attention. Perhaps the Rust implementation improves over the functional languages in some ways, but then it should be said like that. It's not genius, it's just good work.
@ElektrykFlaaj
@ElektrykFlaaj Ай бұрын
@@leftaroundabout I think what's genius about Rust, that it's really a language where the best features of all existing languages were taken and gracefully mixed into Rust, while still being a language with almost the performance of low level languages. You don't have to invent shiny new thing to be genius. You can just be wise and take what works and compile it into something that works even better
@leftaroundabout
@leftaroundabout Ай бұрын
@@ElektrykFlaaj genō (Old Latin) to bring forth as *a fruit of oneself...* ...Anyway, I don't mind Rust being called genius, I mind the lack of attribution.
@henrycgs
@henrycgs Ай бұрын
it isn't. it's pretty much a consensus in the rust community that haskell is great.
@realSimonPeter
@realSimonPeter Ай бұрын
It’s interesting to see how different languages approach the same problems that arose with C++’s constructor design. Swift’s struct init() methods are the same as Rust’s static new methods, in that they can return an optional or throw an error (which must be handled by the caller at compile time, like a Result). However since Swift had to support classes and inheritance for backwards compatibility with Objective-C, it also had to deal with the fragile constructor issue to maintain memory safety guarantees. The way Swift does it is require you to initialize in reverse order: the derived class must initialize ALL its members before calling super.init(…), and it cannot call anything on self until that returns. Nor can it escape a reference to self or access any member other than the ones it already initialized. It seems obvious in retrospect but I think it only works because Swift and ObjC only support single inheritance.
@christopherpetersen342
@christopherpetersen342 Ай бұрын
i've seen a few discussions of implementing both new() and Default::default() but making one call the other (in either direction). does that actually make an API more flexible?
@RoyaltyInTraining.
@RoyaltyInTraining. Ай бұрын
Usually I'd expect new() to create an object with as few assumptions as possible, basically the opposite of default(). If we're talking about a person struct, I'd expect default() to return something like Person { name: "unknown", age: 0 }, while new() should take in name and age as parameters and move them into the struct. You could do this by making default() call new(), which might even be advisable if a struct takes a lot of logic to create. But in this case it would be simpler to just use the struct literal syntax directly in default().
@dovonun
@dovonun Ай бұрын
If I understand this correctly you can't have a function that takes a person or an employee and access the name by using `.name` on the struct. How does Rust work around this?
@jcm2606
@jcm2606 29 күн бұрын
You can if the `name` field is public. If it's private, the convention is to either create a getter function that returns a reference to the field, or to simply not allow external crates to access the field if it could potentially violate some invariant (since you can have fields be publicly visible within your own crate, but not visible to other crates that depend on your crate).
@dovonun
@dovonun 28 күн бұрын
Interesting, i think this allows for some good abstractions. I have to play more with rust
@MT-xb3ts
@MT-xb3ts 29 күн бұрын
Wow, your video animation is fantastically clear, what software do you use?
@Sergio_Loureiro
@Sergio_Loureiro Ай бұрын
How does that constructor approach handle dependency injection?
@jcm2606
@jcm2606 29 күн бұрын
By taking in instances of or references to any dependencies as arguments. Factory functions, which is the actual name for Rust's style of constructors, _are just regular functions,_ so they can take in anything they want as arguments, including instances of or references to other objects. If your object depends on some other object, you can just have your factory function take in a reference to that other object and store the reference within your object.
@mahor1221
@mahor1221 Ай бұрын
Thank you for the video!
@HinaraT
@HinaraT Ай бұрын
02:11 wrong example but if you call introduce in the Person class the override version would effectively not be called as the vtable of Employee is only set once entering the brack of Employee's constructor and "company" field of Employee is missing a type.... I love your videos but please try your code before giving an exemple :/
@nevokrien95
@nevokrien95 Ай бұрын
Idk if rust heavily prioritises simplicity. It's a VERY complex languge compared to something like python or C
@lMINERl
@lMINERl Ай бұрын
I'd agree if someone told me its beginner mistakes if you get some of these errs in C++ but man the thing about rust you dont need to care about anything unless you are in unsafe block and thus far miri is doing a good job pointing out undefined behavior
@letsgetrusty
@letsgetrusty Ай бұрын
Exactly!
@andreaselfving2787
@andreaselfving2787 Ай бұрын
You can use (and should) warnings, and treat warnings as errors, to catch uninitialized values for cpp. I agree that the virtual function call in the constructor is a bit of a skill issue, and just a fact how constructors work. An object isn't actually constructed before the constructor has exited, which makes sense. Constructors do NOT "return a pointer to the object".
@michaelcummings7246
@michaelcummings7246 Ай бұрын
But that is exactly what C++ does the difference is it gives you the option to have an incomplete object when done which is just shooting yourself in the foot.
@elpitbullhouse
@elpitbullhouse Ай бұрын
It's so sad that these basic functional programming features that exist in Haskell and other FP languages since the 90s are though of as "bold" and innovative in 2024 🤦‍♂️
@linkernick5379
@linkernick5379 Ай бұрын
They couldn't unify Async, Option, Result and IO without GC. Actually no one in the whole world knows how to do it with deterministic memory management. This is the thing it is sad really, since monads and algebraic effects are very beautiful abstractions for declarative application programming.
@urisinger3412
@urisinger3412 Ай бұрын
Rust doesn't have a gc
@avwie132
@avwie132 Ай бұрын
@@urisinger3412 That is his point
@urisinger3412
@urisinger3412 Ай бұрын
@@avwie132 that's what makes it special
@JorgetePanete
@JorgetePanete Ай бұрын
thought*
@TheEvertw
@TheEvertw Ай бұрын
Rust has very cleverly understood that a Constructor is in fact syntactic sugar for an implicit factory function. But one with many pitfalls and syntactic problems, which are a direct result of the limitations of the chosen syntax. Then Rust decided that they can do without this implicit factory function, and instead use regular factory functions. BRILLIANT!
@hoyoreverse
@hoyoreverse Ай бұрын
And then OOP fans are still talking about "your rust is missing VERY IMPORTANT thing of programming that is called struct inheritance, how would I represent my [insert some common case] in it!". They probs never tried rust or played w/ it for a week and failed cuz they didn't even try to think different instead of trying to re-invent OOP everywhere
@sunofabeach9424
@sunofabeach9424 Ай бұрын
6 months into rust, and single parent inheritance would benefit it alright.
@Traversed-g8h
@Traversed-g8h Ай бұрын
@@sunofabeach9424 How so? Name a situation that couldn't already by adequately represented using current rust constructs.
@T1Oracle
@T1Oracle Ай бұрын
You should look at the GTK Rust code. They actually made inheritance macros! 🤦🏽‍♂
@TheEvertw
@TheEvertw Ай бұрын
Inheritance of anything except interfaces ('traits') is grossly overvalued. The current consensus is to prefer composition over inheritance, which is exactly the point that Rust makes. The problem is that semantically you can not predict what the result of inheritance will be like. It is easy to violate invariants for the base class in a child. That problem does not exist with composition. In many cases where inheritance would actually be useful, generics will do as well.
@dminik9196
@dminik9196 Ай бұрын
​@@Traversed-g8hWhen working with SQL the result you get back is often flattened. Eg, you might have columns like user_id, user_name, user_avatar_id, user_avatar_url. I've run into cases where I have some fields I will only query in certain situations and also have fields I will always query. Now, there's multiple ways to solve it, but they require support from the library (eg. It's missing from SQLX) or don't necessarily represent what I'm trying to do. Being able to say hey, this struct also has these fields from over here would be great. Maybe something like struct Thing { ..Other, I'd: i32 }
@vcciccv5917
@vcciccv5917 23 күн бұрын
Now I feel confused when building large web projects,c?an you explain how to use rust to achieve clean architectural code
@spoomer94
@spoomer94 Ай бұрын
5:11 but we didn't get the answser is it possible to call specific introduce function within constructor in Rust
@natew4724
@natew4724 Ай бұрын
Use a temporary variable
@jcm2606
@jcm2606 29 күн бұрын
Construct an instance of the struct, bind it to a temporary variable, call `introduce()` on that temporary variable, then return that temporary variable to return the instance of the struct.
@bmx666bmx666
@bmx666bmx666 Ай бұрын
I'm so glad I didn't spend my 10 years learning C++ in depth. And I am so glad that Rust has appeared in the industry.
@Kiyuja
@Kiyuja Ай бұрын
same honestly, tho it sure has a hefty learning curve sometimes
@shosetsuninja3112
@shosetsuninja3112 Ай бұрын
C++ is still heavily used in my industry. I can't imagine any of the long-time C++ experts being willing to switch. It would be safer for onboarding new engineers if they wanted to take this direction, but it would be a huge shift in how things are done. I hope I can be glad I didn't spend 10 years learning C++ and that more and more opportunities to do system level programming emerge for engineers competent in Rust too!
@orterves
@orterves Ай бұрын
Traditional constructors suck because the only failure mode is to throw an exception, so they need to be keep fool-proof, and more complex initialisation has to be moved out of the constructor - but in C# and others, constructors are the backbone of DI so it's hard to avoid them. But everything Rust does here is better architecture; a DI library designed around static new with Result would be an interesting topic
@EE-cc5bd
@EE-cc5bd Ай бұрын
Oh damn thanks. Well this video helped me discover that there is no in-place construct in Rust. Sad.
@Victor-fq6lz
@Victor-fq6lz Ай бұрын
Thumbnail goes hard
@Kiyuja
@Kiyuja Ай бұрын
my jaw just dropped. Even after multiple months of Rust I had no idea this was a thing. My C#/Java brain always wanted to create objects with a New function but that didnt work on my own data types, so I always created structs and thought this is "the Rust way I guess", I didnt even think about creating my own function to return the data type...in this case with "self". OMG, I have to refactor some old code of mine 💀
@mk72v2oq
@mk72v2oq Ай бұрын
Well, then I would say that you are not a very experienced C#/Java developer either. This is a very popular pattern across pretty much all languages called "Factory", Rust didn't invent anything here. I.e. C#/Java devs often do that too due to constructor limitations. For me that was primarily due to lack of async constructors.
@Kiyuja
@Kiyuja Ай бұрын
@@mk72v2oq we use Factories exclusively for when you need multiple instances based on parameters, like HTTPClients or Identities for the DB. I also would suggest you arent experienced in reading either, as this wasnt even what I was talking about. I was talking about something like Person x = new Person(). And if you are telling me that you use a factory for even basic stuff like this, then I will call you a psychopath.
@e.a.p
@e.a.p Ай бұрын
@@mk72v2oq oh shut up
@MrHirenP
@MrHirenP Ай бұрын
Lmao😂
@ShredThatSchecter
@ShredThatSchecter Ай бұрын
Not being able to call virtual methods from a constructor really limits the amount of things you can do in a constructor. This always seemed like a design flaw, which leads you to construct the object and then call a method to initalize things properly
@anon_y_mousse
@anon_y_mousse Ай бұрын
If you think that, then you're misusing virtual methods. If you want a function to call from the constructor then make it private and definitely not virtual.
@DrSoftman
@DrSoftman Ай бұрын
Nice!
@armanradan
@armanradan Ай бұрын
Rust is extremely well thought and it's beautiful! It's a shame that most companies resist to use it more. They say it's too complicated and I agree some aspects of rust like lifetimes and pinning are difficult to deal with, but it's not like rocket science! And you can make it really easy using a little bit of AI help.
@NabekenProG87
@NabekenProG87 Ай бұрын
Adding to this: I learned so much by slogging myself through the complicated parts. It taught me the pitfalls I fell into in other languages without even realizing it. I love C because it taught me how computers work, Rust had a similar role.
@tenspd137
@tenspd137 Ай бұрын
Yeah, you like it, but guess what companies don't want to do - spend the money to replace their codebase that has worked for the last 20 or so years. That's why industry resists.
@skullbearer5067
@skullbearer5067 Ай бұрын
It is also the case that there isn't enough of a pain point being addressed by Rust in a short enough period of return to justify the investment, plus there is the usual mental and emotional inertia to any change decision.
@armanradan
@armanradan Ай бұрын
@@NabekenProG87 Exactly! I've learned so much about threading and shared references in all other languages by learning Rust. And it's not only the complicated parts which teaches us. It always suggests the best way to do things and I'm always amazed by it. I tried to spend more time on Go last month because companies want it more and pay really well for it. Then I learned that Go uses slices instead of vectors and lists. The problem is, when you want to remove an item from a slice, you have to either create a new slice using parts from the original one, or re-arrenge following items manually. Then I came back to rust and called Remove on a vector. It suggested to use swap_remove if order is not important. I tried it and it said this function replaces the reomved item with the last one in the collection. It's amazing that Rust unlike Go, has really high level abstractions (almost zero cost) but teaches us about implementation details and lets us use the best strategy based on our use case!
@armanradan
@armanradan Ай бұрын
@@tenspd137 It doesn't need to replace existing codebase. We can use it in new projects and even microservices.
@lekalotte2825
@lekalotte2825 Ай бұрын
You should have shown modern C++ with default initializers. Showing a coding style from 20 years ago is lame.
@RicardoCapurro
@RicardoCapurro Ай бұрын
Treats c++ features as bugs, do not understand very well how it works or how RAII work!
@hrobertson4
@hrobertson4 Ай бұрын
I love all the amazing concepts Rust has invented for other languages to steal.
@leftaroundabout
@leftaroundabout Ай бұрын
...except, Rust stole most of them from earlier functional programming languages...
@pawewodarczyk1546
@pawewodarczyk1546 Ай бұрын
From my perspective a lack of implicit, or worse undefined, field initialization is a good stuff. What is still missing in Rust are default and named function parameters. Especially a lack of named parameters can be messy when using factory functions for structures having multiple fields and when they are of a same type it's even worse. Kotlin is an example how I would like to see it implemented as a base. Although even there I would like to have additionally an enforced mode where specifying parameter names is always mandatory, not optional.
@ToanNguyen-ue8rw
@ToanNguyen-ue8rw Ай бұрын
You may want to check out the bon crate
@Mankepanke
@Mankepanke Ай бұрын
I was agreeing with you for the longest time, since before Rust 1.0, but now that I've seen bon I'm not so sure we need it anymore :)
@RoyaltyInTraining.
@RoyaltyInTraining. Ай бұрын
I never understood why C++ went with the constructor model it has now. The member initializer list makes having any kind of logic in the constructor excessively hard.
@GiovanniCKC
@GiovanniCKC Ай бұрын
2:20 but why? *why* does that make it call the wrong method? I need to knoooooooowwww
@anon_y_mousse
@anon_y_mousse Ай бұрын
Because the object isn't fully constructed yet and virtual functions are part of the hidden abstractions of construction. Basically, you can expect that any virtual function won't be fully "constructed" until after the end of the constructor function call. The reason is because the virtual functions can be called at any time by the owner of the object after it has been constructed. This allows for objects to be fully constructed before results of that construction are used. Consider also that the super object will be constructed first, and all of its implemented virtual functions will be available then. After that point, the sub object which is inheriting from it will be constructed and its virtual table will be fixed up after it has been fully constructed.
@GiovanniCKC
@GiovanniCKC 25 күн бұрын
@@anon_y_mousse thank you for the thorough and clear explanation :)
@readwrite-p5g
@readwrite-p5g Ай бұрын
I use this best practice of rust
@hiddenau
@hiddenau Ай бұрын
While I like the channel, I wished less time is spent comparing Rust to other languages. The creator of the channel is obviously not a C++ expert and thus not able to provide nuanced examples. Instead I much rather more time is devoted to Rust education.
@Bankoru
@Bankoru 26 күн бұрын
ok but you can also do all that in C#
@tiranito2834
@tiranito2834 Ай бұрын
The things explained around 3:30, how are they any different from how you'd do it in C? I'm genuinly curious, I want to know if there's something else that makes it different. typedef struct { char *name; uint32_t age; } Person; int main() { Person person = {"Alice", 30}; return 0; } If you want a custom initializer with extra logic, then create a function that returns a person, just like what the video says at around 3:40 Person PersonNew(char const *name, int age) { // Custom initialization logic, validation, resource acquisition... Person ans = {name, age}; return ans; } As you said, that's just a regular function, so what difference does it have from this? And if you want result types, then what's the difference with this? int PersonNew(Person *self, char const *name, int age) { if(age < 18) return 1; self->name = name; self->age = age; return 0; } int main() { Person person; int success = PersonNew(&person, "Alice", 30); if(success != 0) { printf("Error : %s ", GetErrorStringPersonNew(success)); return 1; } return 0; } And if you don't like the C style of using an integer status and translating it to a static error string, you can always do it in a more Rust-like style with return structs that contain a value and an error status.
@furno_2761
@furno_2761 Ай бұрын
Afaik the only difference is that in rust you have to specify the values of all fields.
@tiranito2834
@tiranito2834 Ай бұрын
@@furno_2761 I guess you mean when using the brace initialization in C, no? True, you can indeed not initialize all values, but if you use a function you can still enforce initializing all of the fields. In any case, for any complex struct with advanced functionality it would make sense to make use of explicit functions for "construction" / initialization. Also if we're strict when thinking about the differences, I guess also the ownership of the pointers and stuff, but there is not a string struct in C, and functions called with dot notation technically compile to a function call that takes a "self" / "this" pointer as a parameter, and this holds true for C++ and Rust, so even then in this example it would not be a relevant difference, cause the functions are handling all of that logic internally so it's literally just the same as in Rust.
@BartKus
@BartKus Ай бұрын
Honestly this is all doable in C++ with a couple compiler flags and clang-tidy calls. If you wanna stick to using factory functions instead of constructors you're free to do so as well. But give it 10 years and the explicit verboseness gets tiresome, and you'll reinvent constructors and also call it some new wonder of programming language design. I'm too old for all this, get off my lawn.
@codeline9387
@codeline9387 Ай бұрын
what about jobs?
@pedrogaxiola9140
@pedrogaxiola9140 Ай бұрын
Dang. I thought this was an R (stats) video 😅
@discreaminant
@discreaminant Ай бұрын
C++ diffs Rust in terms of in place allocation In Rust, u can only rely on optimization, so good luck on the debug mode (stack overflow), or unsafe Rust could never
@stevenspungin6704
@stevenspungin6704 Ай бұрын
Traditional constructors also cannot be async, wheras Rust constructors can be.
@Maskrade
@Maskrade Ай бұрын
factories:
@torarinvik4920
@torarinvik4920 Ай бұрын
I am one of the few that disagree with the composition over inheritance slogan. I follow the rule 1. "Is a" means inheritance or interface. 2. "Has a" means composition. 3. "Uses a" means delegation. I rarely do use inheritance though, as I usually use algebraic data types with pattern matching instead. This gives me a more flexible form of polymorphism, where I can do multiple dispatch and more. It's incorrect to say that an Employee has a Person, that doesn't make sense. In this case I would rather just use good ol' fashion code duplication.
@jcm2606
@jcm2606 29 күн бұрын
At least IMO, when dealing with data inheritance (ie you're inheriting some data from an abstract type), "has a" is virtually equivalent to "is a" if you have an adequately abstract public API. If you have some object `A` that has an instance of some object `B` stored inside, and `A` has a number of methods that silently accesses things from the inner instance of `B`, does it really matter to an outside observer if `A` is an instance of `B`?
@torarinvik4920
@torarinvik4920 29 күн бұрын
@@jcm2606 To be honest I don't quite understand what you mean. I do agree that inheritance is fragile though and that interfaces should be used unless you have a good reason to use inheritance over it.
@lesliejohnrichardson
@lesliejohnrichardson Ай бұрын
18 Minutes ago is NOT crazy
@HosseinOjvar
@HosseinOjvar Ай бұрын
Rust is GOD
@hermes6910
@hermes6910 Ай бұрын
1:25 Not the best example, just use uint, even better uint8_t ?
@yondaime500
@yondaime500 Ай бұрын
The C++ Core Guidelines say "No, using unsigned is not a good way to sidestep the problem of ensuring that a value is non-negative."
@hermes6910
@hermes6910 Ай бұрын
@@yondaime500 because of possible problems at runtime ?
@spik330
@spik330 Ай бұрын
2:11 now that just sound like a bug in the way C++ handles method initialization, as this is undefined behavior.
@dshindov
@dshindov Ай бұрын
I couldn't reproduce this example tbh
@jmsdnns
@jmsdnns Ай бұрын
I wanna have like 500 of Rust's babies. I think I'll use this pattern when each baby is born.
@azharalibhutto1209
@azharalibhutto1209 Ай бұрын
❤❤❤❤❤❤❤❤❤❤❤
@anon_y_mousse
@anon_y_mousse Ай бұрын
Rust constructors are one of its biggest flaws. It's basically forcing you to use Java in a C-ish way. What's worse, is that because the constructor can be renamed to whatever the developer wishes, it even provides an extra avenue of guesswork. This means that either everyone uses one naming convention and then why should you have to name it at all, or it forces you to look it up in the documentation/code. All of the extra garbage that you have to add such as .to_owned() and .into() and either using .unwrap() or match and a clunky switch-esque syntax just adds to my list of annoyances. Not that I would expect a brainwashed zealot to understand this complaint, and you've certainly never responded to my messages so why start now, but easy things should be easy and hard things should be hard yet Rust and far too many new languages like to make the mistake of inverting responsibility. It really screws up the mind of a newbie if they learn with one of these backwards languages because they don't understand the fundamentals of how anything works.
@RustIsWinning
@RustIsWinning 26 күн бұрын
Holee the amount of copium tanks again LMAO 🤣
@anon_y_mousse
@anon_y_mousse 26 күн бұрын
@@RustIsWinning I know, you don't understand how things work, it's okay.
@RustIsWinning
@RustIsWinning 26 күн бұрын
@@anon_y_mousse My guy can you even remember the 3 letter word "new"? LOL! Maybe a bit C-nile if it is so hard to know simple conventions ROFL. Write as much garbonzo as you want like the other 33 comments here. Rust is living rent free in your head hahaha
@RustIsWinning
@RustIsWinning 24 күн бұрын
@@anon_y_mousse What do I not understand? The fact that there are people who complain about a 3 letter naming convention because the language was designed that way? Okay buddy if that's the problem maybe go see a doctor LMAO
@anon_y_mousse
@anon_y_mousse 24 күн бұрын
@@RustIsWinning What you're saying makes no sense and doesn't apply to what I've said here.
@floppypaste
@floppypaste Ай бұрын
Althoug i absolutly agree with the overall message of the video, there is one thing i disagree with: Rusts Result type is actually not that different to plain old exception handling (but more consistent, as it is part of the language), even in your example the caller needs to know which errors can be trown to handle them accordingly.
@Mankepanke
@Mankepanke Ай бұрын
Checked errors is one of the things that make it good, though. Not a downside, but the point of it.
@jcm2606
@jcm2606 29 күн бұрын
I'd more so say that it's not that different to checked exceptions, since plain old exceptions can be thrown anywhere and you won't know until your program either crashes randomly, or the exception is caught in some obscure try/catch statement somewhere down the call stack. `Result` and checked exceptions both at least tell you that some code can possibly produce an error, and they both force you to handle that error. The main advantage of `Result` over checked exceptions is that it's part of the type system and so naturally benefits from Rust's rich type system.
@fischi9129
@fischi9129 Ай бұрын
Idk, half of this video sounded and there is a pitfall if you don't know about it... well yeah, you should know the lang you are using ngl...
@bothorsen4292
@bothorsen4292 Ай бұрын
The constant C++ bashing on this channel is getting old very fast
@Greeem
@Greeem Ай бұрын
I kinda agree. I liked this content at first and now it just feels like rust worship. All of the "issues" defined in this video are PEBKAC.
@EliteCPR
@EliteCPR Ай бұрын
@@Greeem nah, footguns are bad design and should be treated like it
@RustIsWinning
@RustIsWinning 26 күн бұрын
The only thing I see here that is getting old very fast are the dinosaurs that cope. Dont forget to this one boomer --> ♿️
@bothorsen4292
@bothorsen4292 26 күн бұрын
@@RustIsWinning wow, you really are clueless
@RustIsWinning
@RustIsWinning 25 күн бұрын
@@bothorsen4292 Clueless about what? Alright wrong generation I guess. But still take these to cope: ♿️💊
@olafbaeyens8955
@olafbaeyens8955 Ай бұрын
One thing I did back in C++ and C# is to make sure that nothing in a constructor can fail. A constructor has 100% guaranteed initialization. I have a second method Init() that can fail and gives an indication that the code is doing something more than just initializing variables. This Init() can also be reused later in my code to reset the initial state, so I don't need another constructor and memory allocation. Just reset it and I do not have to update pointers everywhere. When I create the Init(), I also create the Reset(), which calls the Init() internally, so developers using my code have a clear description of what it does. You see something like: var myClass = new myClass(); myClass.Init(); Variation could also be var myClass = new myClass(autoInit= true);
@NotherPleb
@NotherPleb Ай бұрын
In c++, 2 step initialization goes against the their guidelines, they actually recommend throwing exceptions
@hoyoreverse
@hoyoreverse Ай бұрын
But that allows you to have broken (not fully initialized) state. And it's obviously not "if it compiles, it works" then cuz you may forgot to call init() and there's no compile-time check for that
@ClimateChangeDoesntBargain
@ClimateChangeDoesntBargain Ай бұрын
the problem with inits is that you can forget to call init and have a object in a partially constructed state.
@olafbaeyens8955
@olafbaeyens8955 Ай бұрын
@@NotherPleb Exceptions cause great misery in the end, because they are like GOTO's, you have no idea where it ends up. Your catch blocks become huge blobs of code, bigger than your functional code. Giant catch blobs make you hide the real functionality that is called 99.9999% of the time.
@olafbaeyens8955
@olafbaeyens8955 Ай бұрын
@@ClimateChangeDoesntBargain But still safe to use because it is a predictable state.With an exception it jumps back to a random place and also have no meaningful information that helps a user.
@Cathyprime
@Cathyprime Ай бұрын
Literally you can make a private constructor and have static methods to create the object, as a mater of fact you can do shit like that in any language supporting methods for classes... this isn't some great rust feature...
@ThisIsNotAUsername-v3o
@ThisIsNotAUsername-v3o Ай бұрын
Rust does make it easier to notice, since the constructor factory pattern is explicit. As a preference note, out of C#, C++, and Python, I do prefer Rust.
@EpKjelltzer
@EpKjelltzer Ай бұрын
The great Rust feature is that it doesn't support the other ways, because they're known to cause issues. The feature is not "you can construct and return an object via a function", it's "there's no such thing as a constructor, aka a special function with lots of pitfalls".
@ThisIsNotAUsername-v3o
@ThisIsNotAUsername-v3o Ай бұрын
​@@EpKjelltzer That is true; I didn't address that part because it seemed tangential to the point under discussion. That being said also, having no software-defined convention for constructing an instance of a type is also a potential pitfall. The perfect programming language is a verb, not a noun.
@Cathyprime
@Cathyprime Ай бұрын
@@EpKjelltzer MyClass() = delete;
@williamdroz6890
@williamdroz6890 Ай бұрын
IMO C++20 concepts are the only thing that C++ is doing better than Rust.
@T1Oracle
@T1Oracle Ай бұрын
Unfortunately, all of those legacy features that should have been discontinued decades ago, are still part of the language. So you still have to deal with the possibility of someone using them. Which is tough, because there are so many features. Even with decades of experience, you will still not be aware of every feature, and every syntax trick, in C++. Then you have macros, templates, and a plethora of memory and thread safety issues.
@tenspd137
@tenspd137 Ай бұрын
And guess what - you are going to get just as many problems, just different ones, with rust.
@KhaledKimboo4
@KhaledKimboo4 Ай бұрын
This is a freaking religion, you guys are overly hyped over a language that ENFORCEs someone's idea of a good constructor onto you, just get better with any language you use. Hyped like It's God have sent the holy grail of constructors. is see rust suitable for programmers with "tell me what/how to do" mindset
@antifa_communist
@antifa_communist Ай бұрын
It's better though.
@antifa_communist
@antifa_communist Ай бұрын
It forces you to so something correctly. How is it bad to stop you from doing something wrong? Why would I want my fields to be possibly uninitiated? Have you even tried Rust?
@pierreollivier1
@pierreollivier1 Ай бұрын
I think the main benefit of explicitness is to prevent insidious bugs. Explicitness is good, languages that try to hide every single low level details and focuses on making it easy to write, are optimizing for the wrong metric, C++ constructor are just poorly designed, like most of the language is, I'm saying that as someone dealing with C++ on a daily basis, it's such a bad language, fortunately enough I'm able to rewrite most of it.
@jcm2606
@jcm2606 29 күн бұрын
The funny thing is that your argument applies much more strongly to C++ and other languages with constructors than Rust, because Rust doesn't even have constructors. What Rust has is associated/static functions, which are just plain old functions that just so happen to belong to the struct's namespace, making it convenient to relate the function with the type. A Rust "constructor" is literally just a plain old function that wraps the primitive construction of the struct, so that "someone" is actually _you,_ since _you_ are the one who dictates how _your_ "constructor" works, the language just gives you an associated function as a starting point.
@pierreollivier1
@pierreollivier1 29 күн бұрын
@@jcm2606 Exactly, that's the same has having an init function in C where you pass a pointer to your struct, or arguments and get an initialized struct of your type, nothing fancy, just good old function, without 30 overloading, simple, easy to reason about, effective.
@kleinmarb4362
@kleinmarb4362 Ай бұрын
4:35 syntax error in the second line of Person::new
@buycraft911miner2
@buycraft911miner2 Ай бұрын
isnt "Ok Self... " meant to be "Ok(Self...)"​?@@Traversed-g8h
@clot27
@clot27 Ай бұрын
Rust hype
@abcq1
@abcq1 Ай бұрын
There's nothing wrong with C++ constructors. As you fairly said, when someone "doesn't know nuances" (which translates to just not knowing enough of the language and being immatiure programmer), he writes shit. Know your rlanguage. After which there are no problems.
@pierreollivier1
@pierreollivier1 Ай бұрын
There come a point where if too many people have a "skill issue" with you language, your language as design issues. C++ is overly complex for no benefit, there never was a point in my life where I couldn't have generated the same assembly in C, Zig, Rust or any other compiled language. I'm not saying the language is completely useless, but the way people can't recognize how flawed the language is, is quite ridiculous, think about it if one can generate the same assembly, in a safer way, while being more readable and easier to maintain, with less pitfalls, then what is the actual proposition value of C++, what are the benefits of using C++ over any other LLVM powered language ? I just don't get why people use a low level language, to then hide every single low level detail behind walls of abstractions. The only good C++ I know is the one where you write C code, and use a few containers where it make sense.
@antifa_communist
@antifa_communist Ай бұрын
Even experienced programmers get this wrong though. It's objectively bad. You said yourself you have to know all these nuances.
@4lxprime730
@4lxprime730 Ай бұрын
rust is overrated right now, peoples must look at more balanced languages such as golang or zig
@knnk4000
@knnk4000 26 күн бұрын
sorry, not a gomonkey or a zigay :)
@RustIsWinning
@RustIsWinning 26 күн бұрын
We found the gobesse zigooner lmao
@4lxprime730
@4lxprime730 26 күн бұрын
@@RustIsWinning that's funny, keep building your software with overcomplicated languages, i prefer the simplicity
@RustIsWinning
@RustIsWinning 25 күн бұрын
@@4lxprime730 The real funny thing here is that go is slower and zig is not even memory safe haha
@4lxprime730
@4lxprime730 25 күн бұрын
​@@RustIsWinning go is way more efficient to write than most languages (including rust btw) and is not meant to be as fast as c, just to get things done. zig is as fast as rust (can be faster with its allocator system and can be slower) and have all that you may want from a modern language including some safety. The problem with the rust hype is that you are only talking about safety which is a bit delusionnal cause safety is a human problem, you can do code as safe as rust's in c with 10x less complexity
@markg5891
@markg5891 Ай бұрын
Ohh definitely not! Rust and simplicity do not go hand in hand! Rust just has a different syntax that "resembles" c/c++/java but is still way different! It's generally agreed to be a more complex syntax compared to c/c++/java. The C++ example given is true but calling it an "unintentional bug" is stretching it, i'd call it a bad developer. Sure, these are some of the more intricate C++ details you need to get right when developing in C++. Like rust has weirdness (borrow... anyone), C++ has other weirdness. Rust avoids pitfalls, sure, but introduces many new of it's own. Rust is still an amazing language! :)
@letsgetrusty
@letsgetrusty Ай бұрын
Agreed, every langauge has rough spots and weridness. I'm curious to know what pitfalls Rust has in your opinion
@EpKjelltzer
@EpKjelltzer Ай бұрын
I don't think you can say that Rust's syntax is more complex than Java or especially C++. Definitely there's an argument to be made about semantics (although nothing is as complex as C++'s semantics), but Rust's syntax is really not complex. Perhaps unfamiliar, but not complex. The big difference is that Rust's "pitfalls", at least based on the most common complaint's I've seen, are compiler errors that people have a hard time understanding. And that's definitely complex, but in a completely different way than the C++ pitfalls that seem to work until your program blows up in a way that is extremely difficult to trace to the original bug. You would call the developer bad rather than blame the language when the C++ bug is encountered, and yet we now have many decades of proof that there's no such thing as a "good" developer if we assume that to mean someone who doesn't introduce subtle bugs. So the only clear way forward is to expect more from our tools. I would call it a failure on C++'s part to allow developers to write clearly bad code.
@NotVersace
@NotVersace Ай бұрын
"bad developer" causes "unintentional bug". That's the point. By avoiding pitfalls as part of the language design you have less unintentional bugs as a result of bad developers.
@markg5891
@markg5891 Ай бұрын
@@EpKjelltzer Some nuance on the "bad developer" part. I said that with the assumption of developing in C++ is using it's inheritance model. These inheritance pitfalls (and there are many) are just the learning curve of using C++ with inheritance. A good developer (where good means someone who knows how to write C++ and actually learned the language over years) either instinctively knows these cheap-shot pitfalls and thus prevents them or knows how to run the code to detect falling for the same trap and fixes it. A developer that knows other languages and just takes a dab into C++ (without learning it, just applying logic from different languages to rust and assuming it to work the same) might well be able to build something that compiles and runs. But will also fall for the pitfalls and then have a hard time finding out why it happens. It might still be a great dev! I agree with you that tooling can help massively here!
@pierreollivier1
@pierreollivier1 Ай бұрын
There come a point where you have to consider that if everyone is having "skill issues" with your language, than maybe your language is the problem. I don't see why companies like Google, Apple, Microsoft, would go out of their way and spend so much on running away from C++ by developing their own languages (Swift, Go, Carbon) or using newer one (Rust) if C++ was so great, If your language needs 2300 pages of ISO specs just to defines itself when C barely scratches the 800 marks, I think we just need to call it a day and move on from it. C++ is just too complex, too bloated, poorly designed. I'm glad newer languages are coming to fix this mess.
@sunofabeach9424
@sunofabeach9424 Ай бұрын
isn't this achievable in like any other language? just uhh define it explicitly and make constructor private
@jackkendall6420
@jackkendall6420 Ай бұрын
What rust gives you is the *guarantee* objects will always be fully initialised. You don't have to rely on everyone else making their ctors private and giving you factory functions.
@sunofabeach9424
@sunofabeach9424 Ай бұрын
@@jackkendall6420 it will be initialized fully but not always correctly. that's why you will most likely create a 'new' function, basically, returning to constructors. so it basically boils down to patterns: in Rust you need to define constructors, in OO languages - make them private. and while the former approach is more clean, there is nothing 'genius' to it
@diadetediotedio6918
@diadetediotedio6918 Ай бұрын
No, it is not. In C# for example you can have null values and structs can be 'default' initialized, so making their constructors private don't ensure correctness. In Rust you to initialize things.
@CjqNslXUcM
@CjqNslXUcM Ай бұрын
​@@sunofabeach9424 Yeah, it's rather banal. But you'll appreciate it when you work with other people's code.
@sunofabeach9424
@sunofabeach9424 Ай бұрын
@@diadetediotedio6918 nulls and constructors are unrelated to each other. you can have a language without nulls but with constructors
@andreaselfving2787
@andreaselfving2787 Ай бұрын
I still think go is a better option for developers coming from any other high-level languages, such as python etc
@frydac
@frydac Ай бұрын
depends on your definition of better. There is no one that is best in all contexts, the answer to almost any question is 'it depends' (google kevlin henney - it depends )
@korniychuk
@korniychuk Ай бұрын
Test for a "good programmer" 😃 If a programmer appreciates Rust's principles, strictness, and limitations, they are a good programmer. Writing code in other languages, such a programmer tends to write strict code, keeping Rust's limitations and principles in mind, even though the other language is less strict and more error-prone. A "bad programmer" dislikes all of Rust's reliability principles and limitations and prefers not to write code in Rust. Instead, they write fragile code without any safeguards in less strict languages and think "it's easier and faster, what's the problem?!". 🫠
Ultimate VS Code setup for Rust development (2025)
7:32
Let's Get Rusty
Рет қаралды 30 М.
8 deadly mistakes beginner Rust developers make
14:14
Let's Get Rusty
Рет қаралды 172 М.
Disrespect or Respect 💔❤️
00:27
Thiago Productions
Рет қаралды 38 МЛН
Миллионер | 3 - серия
36:09
Million Show
Рет қаралды 1,2 МЛН
How To Choose Mac N Cheese Date Night.. 🧀
00:58
Jojo Sim
Рет қаралды 49 МЛН
Triple kill😹
00:18
GG Animation
Рет қаралды 18 МЛН
The magic of Rust's type system
9:01
Let's Get Rusty
Рет қаралды 79 М.
Being Competent With Coding Is More Fun
11:13
TheVimeagen
Рет қаралды 111 М.
Why Rust is NOT a Passing Fad...
8:54
Travis Media
Рет қаралды 43 М.
State Pattern in Rust | Rust Language
20:21
Learning Rust
Рет қаралды 2,2 М.
why rust libraries may never exist.
7:26
Low Level
Рет қаралды 274 М.
Object-Oriented Programming is Embarrassing: 4 Short Examples
28:03
Brian Will
Рет қаралды 2,1 МЛН
Why do developers hate Rust?
8:20
Let's Get Rusty
Рет қаралды 140 М.
Cursed C++ Casts
17:41
Logan Smith
Рет қаралды 74 М.
5 things I wish I knew before learning Rust
7:28
Let's Get Rusty
Рет қаралды 132 М.
Disrespect or Respect 💔❤️
00:27
Thiago Productions
Рет қаралды 38 МЛН