5 ms·
The point is, Rust is vastly easier than C++ when you start factoring in the complexity of debugging nasty design choices that comes to bite you in the back and
by qalmakka 4y ago
The point is, Rust is vastly easier than C++ when you start factoring in the complexity of debugging nasty design choices that comes to bite you in the back and you can't really fix without tearing the whole application apart.
Yesterday I was fighting the borrow checker because it wasn't allowing me to pass a reference in an async function. After a while it dawned me that if that thing I was attempting to write would have been accepted, it would have caused a crash in some rare, but not impossible, circumstances.
It saved me potentially countless hours of debugging and wrapping my head around the fact that my smart abstraction crashed every once in a while, something that happens to me everyday with C++.
Rust is hard, but it's less hard than it's alternatives.
- pjmlp 4y agoDunno, maybe it is Stockholm syndrom from using C++ since 1993, but I definitly find easier to understand template metaprogramming than the upcoming GAT, or the whole Pin and PhatomData stuff.
- Ygg2 4y agoSure, but you are comparing meta programming facility to a type/lifetime feature that serves as Higher Kinded Type replacement. In Rust same thing holds, macros are easier than GAT I don't get why PhantomData or Pin are that hard to grasp? PhantomData is just a type marker that has no purpose other than help compiler. See https://doc.rust-lang.org/nomicon/phantom-data.html https://doc.rust-lang.org/nomicon/phantom-data.html Pin is a way to create self referential structs, by pinning memory and preventing moves. PhantomPinned is a marker type to ensure your type is not Unpin (it is by default). Unpin it thing that shouldn't be pinned, like bool, i32, etc.
- qalmakka 4y ago> Pin is a way to create self referential structs, by pinning memory and preventing moves. This, exactly. Pin works more or less like a C++ class with a deleted move constructor. Copies may be allowed if clone/copy (aka, the implicit/explicit copy constructor) are defined, but move and RVO are not. Lots of Rust's concepts can often be described in terms of C++'s techniques, but more often than not in C++ it tends to be a hack, while Rust has a formalism for that, like Pin for instance. In C++ you can have moveable self-referencing structs because you can update the self references in the move constructor, but moves in Rust are always memcpy - which is saner IMHO than the whole move constractor and rvalue shenanigans.
- ridiculous_fish 4y agoHow does this work? I want to wrap POSIX semaphores. You call sem_init, passing it the address of an int; later you call sem_destroy and pass it the same address. So the location of the int must not change. In C++ you would delete the move constructor: struct sema { int v; void sema(sema &&) = delete; }; In Rust you might try this, but it doesn't work: struct Sema { v: Pin<i32>, } there is no way to create a "Pin<i32>". The closest you can get is probably to malloc it: struct Sema { v: Pin<Box<i32>> } but now Pin is adding nothing at all (except perhaps a hint to the reader) and may be deleted. The real guarantee is provided by Box, not Pin. It looks to me like Pin is created to support async, and outside of that use case is not very useful, and is a poor replacement for non-movable types.
- Ygg2 4y ago> there is no way to create a "Pin<i32>" Caveat, I haven't worked with Pin that much. Take this with a grain of salt. My understanding is - you really shouldn't put copyable stuff in Pin. Period. If you want something like that wrap i32 in new struct and declare it !Unpin. Since negative traits are unstable, you just write PhantomPinned marker struct NonPinI32 { v: i32, non_pin: PhantomPinned, }
- steveklabnik 4y agopin is purely a property of a pointer, so Pin<i32> doesn’t make sense. While you’re right that Box gives you a stable address, you can still move out of a Box, or swap something into the Box. Pin<Box<P>> prevents that.
- pjmlp 4y agoI am only listening some of the concepts that I find harder to grasp, regardless of the context. Macros are easier than GAT, maybe, there is a whole talk how serde goes crazy with macros. PhantomData or Pin are hard to grasp, not as concept, rather to keep track when they are needed, many times it isn't clear that the way to fix some compilation error is to plug one of those types. A bit like having to do references to constant literals as well, another gotcha.
- estebank 4y agoIf you encounter a case where the solution to a problem was PhantomData or Pin, and the compiler doesn't flat out tell you that, file a ticket.
- Ygg2 4y ago> PhantomData Usually when you want to give type some information it wouldn't normaly have. Like e.g. using it to store generic type signature for some kind of SQL builder. or to keep a lifetime that would otherwise be unbound. > Pin Just for self-referential structs. Since async relies on self-referential, it might also require it. --- When to use it? When you either exhaust all other options or know enough to judge it worthwhile.
- deleted 4y ago[deleted]
- qalmakka 4y agoI've seen people picking up C++ from scratch recently and rest assured, that's not so obvious for a novice like it is for a person that's been using it for decades. I think the level of complexity is similar, but at least Rust features feel like they were designed on purpose. C++ metaprogramming, to be fair, is a happy little accident that turned out being a blessing, more than something that was well designed from the start...