5 ms·
(Disclaimer: I'm not a rust expert by any means so bear with me, I'm also genuinely interested in the language) * While not perfect, C++ has a few package mana
by Ragnarork 4y ago
(Disclaimer: I'm not a rust expert by any means so bear with me, I'm also genuinely interested in the language)
* While not perfect, C++ has a few package manager that are quite solid (personal favorite being conan).
* What can Rust macros do that C++ TMP (and macros even though that's a last resort IMHO...) can't do?
* From what I've gathered, it's similar in complexity to using the CRTP in C++, maybe a bit less verbose. Am I missing something?
* I feel like "interfaces" as in pure abstract virtual classes can achieve the same effect as Rust traits (though it could be its own thing and not a special case of a class specification), and the newly introduced Concepts goes even further that what can be achieved.
Don't get me wrong, I like the improvements rust brought, especially in terms of safety, but other than that... I don't think C++ is particularly far, or even actually behind for some of these.
- sqeaky 4y agoC++ dev here, not a rust dev. It is my understanding that Rust macros have some understanding of the syntax/parse tree, making them much safer than text replacement like c++ macros. A better comparison to Rust macros might be constexpr and template meta-programming.
- lifthrasiir 4y ago> What can Rust macros do that C++ TMP (and macros even though that's a last resort IMHO...) can't do? I'm not sure why you specifically compare Rust macros with C++ TMP. Rust macros are meant to be a safer and more flexible alternative to C/C++ macros, not else. C++ TMP is not a goal but a means to the goal, so if you look for something like TMP in Rust you will see nothing (the closest is generics, but of course it doesn't subsume TMP because it needn't). The goal of TMP is generically a compile-time metaprogramming and Rust has multiple solutions for this, including but not limited to generics, Cargo-directed code generation (via `build.rs`), macros by examples (`macro_rules!`) and procedural macros. > From what I've gathered, it's similar in complexity to using the CRTP in C++, maybe a bit less verbose. Am I missing something? CRTP (curiously recurring template pattern) is really aptly named and it is a testament to C++'s accidental complexity. I don't think any new C++ user can discover CRTP in reasonable time. In Rust traits are built-in and well incorporated into the core language. > I feel like "interfaces" as in pure abstract virtual classes can achieve the same effect as Rust traits (though it could be its own thing and not a special case of a class specification), and the newly introduced Concepts goes even further that what can be achieved. You have a generally right idea about traits that it is conceptually similar to concepts, but I believe there is currently no equivalent of `dyn Trait` for concepts. There was no effort to harmonize concepts and existing virtual classes. Also your parenthesized remark is more important than you imagine; `dyn Trait` in Rust is implemented as a fat pointer, which decouples vtables from instances and is generally much less complex than C++ vtables which have to account for multiple inheritance for example. As a C++ programmer you may feel like that you want a choice between vtable and virtual methods vs. no vtable and no virtual methods, but it is a false dichotomy and Rust gives the best of both "choices".
- trilobyte 4y agoCargo is one of the best package managers and build tools I've used. They seemed to really look across all of the problems in the ecosystem and try to bring in the best features while leaving it open to extension. I have yet to see another one that checks all the same boxes.
- saurik 4y agoCargo is built in a way that makes it very difficult to avoid and yet it fails to understand basic cross compilation cases correctly which make it (ironically) infuriating for people working on embedded use cases as well as for people attempting to do production binary deployments. Meanwhile, the tool just fundamentally refuses to support reproducible builds in such scenarios even though Rust is fully capable of it (I finally had to write a wrapper for the Rust compiler to munge a the arguments passed by Cargo to remove their semantic mistakes). I feel like the problem is that it isn't just a package manager... it insists on simultaneously being not only "a" but "the" build tooling, which is trading way too much flexibility for a very small amount of convenience. And like, OK: maybe this is useful for people who are just getting started, but I would firmly argue that this kind of tooling should consider the needs of the expert and not make severe tradeoffs for the needs of the beginner unless it is trivially and obviously optional and there can be growth through changes in tooling (where maybe people "graduate" from Cargo to a more extensible tool... but since it is also the package manager, that's brutal). The issues for the tool are then riddled with bugs that have been open for years (I think some of the ones that I've been blocking on might already be at 5 years, which is shocking to me as I don't even think of it being very old) that even often have multiple reasonable pull requests filed but where no progress ever gets made on fixing the problems because, even though it is often trivially shown that there is no way to use the tools correctly currently in the general case, they insist that the behavior of a working tool might break some theoretical user relying on the current inconsistent set of behaviors. The result of all of this is that there are a ton of workarounds for Cargo that projects have started to have to embed almost as boilerplate into their projects, including a popular one that is going around right now (required for Linux->Linux cross) involving setting an environment variable that explicitly tells the user not to set it ever in the name of the variable but like... Cargo doesn't be have any other way of making this stuff work correctly. It is honestly infuriating and ridiculous and there are good reason why you keep seeing stuff like Google avoiding it entirely as part of their Bazel integration.
- tialaramex 4y ago> What can Rust macros do that C++ TMP (and macros even though that's a last resort IMHO...) can't do? Rust has two kinds of macro with very different properties, so lets talk about that briefly (reader: if you are here to learn about this C++ Proposal paper then er, bye?) 1. The macro_rules! "By example" macros. These are a bit like the simpler C macros you might have used, except that they really care about syntax and aren't just gluing text together without understanding it. These macros are hygienic (if a macro uses its own variable named "count" and your function has a variable named "count" Rust knows those are different variables and everything works fine whereas with a C or C++ macro that will cause trouble) and they're fairly powerful for solving those annoying "Don't Repeat Yourself" problems in programming when you can't quite factor out the repetition in the Rust code per se. These macros are very safe, I would trust a novice to write and use them, worst case maybe you need to show the novice how to ask Rust to apply the macro and show the results so they can see what they screwed up, because e.g. "suck it and see" doesn't work very well to figure out what you did wrong writing a macro. 2. Procedural ("proc") macros. There are several specific flavours of proc macro but they're all Rust code, which you wrote, running inside the compiler during the build, taking bits of the program syntax tree as input parameters. This can do anything. For example Mara wrote whichever_compiles! a proc macro which forks the compiler, attempting each of the options you supplied, once one of them compiles the other compilers die and the survivor presses on compiling the rest of your program. It's deeply regrettable that this is possible, but it is. Only experts should touch proc macros, and they should obviously not do anything crazy unless (like Mara) they are doing so as a joke. So, proc macros can do a lot more than C++. Perhaps more than they should do, but more. > I feel like "interfaces" as in pure abstract virtual classes can achieve the same effect as Rust traits C++ traits are roughly in the same space as C++ 0x Concepts. You might think aha, we have C++ 20 Concepts. Unfortunately C++ 20 Concepts is a pale shadow. Traits does a few important things (possible to some extent in C++ 0x Concepts) which C++ 20 Concepts can't do. In particular, it has semantic weight because the concepts must be explicitly implemented. In C++ two concepts with the same syntactic requirement are functionally identical. The ISO document says using a concept which is not correctly "modelled" means your program is ill-defined (might do anything) but in practice the code compiles and everything seems OK. In Rust even though there's no syntactic difference between PartialEq and Eq, the types which don't explicitly implement Eq are not Eq. That is, you can programmatically ask, "Is a == b an equivalence relation?" whereas in C++ all you can actually ask is "Can I write a == b ?" More directly practically, Rust actually checks Traits whereas in C++ there is no checking. e.g. if you try to sum() a Vec of u32s that will work, but if you try to do that to a Vec of Strings there is no such function, the Sum Trait isn't implemented for Strings. You could do this in C++ but it's much easier not to, and so most software doesn't and then your users are fed a lot of SFINAE compiler errors which choke them to death. In Rust it's mandatory to spell out the required Traits.