6 ms·
To me it's almost the opposite. I like C a lot, but I ended up compromising on C++11 because in some programs I need more features to keep the implementation c
by zerofan 10y ago
To me it's almost the opposite. I like C a lot, but I ended up compromising on C++11 because in some programs I need more features to keep the implementation clean. I pay the cost of a messy language (C++) when implementing my libraries in order to have simpler applications that use those libraries.
I've written C-like programs in Rust, and that goes very well. But I really like function overloading, generic operators that I can overload from the left and the right, integer parameters for my templates/generics, copy semantics as the default (opt-in for moves), placement new, explicit destructors, and maybe a few other niceties. Rust does none of these things the way I want, and so I'm stuck with C++.
There are a few other things where I think Rust just made the wrong choices and didn't improve over C++. I've always hated the dichotomy in C++ strings between const char* pointers and an actual string class. Rust had the chance to make strings feel as comfortable as integers, but instead they introduced their own dichotomy with String and &str.
Speaking of integers, Rust's choice of 32 bit integers as the default for literals is painful given that every machine most of us will ever care about is now 64 bit. I routinely deal with arrays and files that are too large for a 32 bit integer. This means I have to remember to suffix all of my integers in for loops etc... C++ has this wrong too (backwards compatibility), but Rust had a chance to make a clean start and did not.
- gpderetta 10y ago> But I really like function overloading, generic operators that I can overload from the left and the right, integer parameters for my templates/generics, copy semantics as the default [etc.] I do too, and I'd like to think that rust needs all those things to be a replacement, but realistically I think that the only killer feature that rust is still missing is reasonable interoperability with C++ (which admittedly might require implementing a few of those features). Disclaimer: I have been following rust since Graydon initial announcement, but I have yet to write a single line of code in it.
- akiselev 10y agoWhat do you mean by "reasonable?" There are several crates that provide inline C++ macros on both nightly (rustcxx) and stable (rust-cpp). I haven't used the latter but the former works really well (albeit using a gcc specific feature). I usually break out the C++ code into a wrapper (unless its a few lines) to make it more idiomatic Rust but at the end of the day, there aren't that many hoops to jump through.
- steveklabnik 10y agoHow would you have gone about making Strings be "as comfortable as integers"? Arrays are indexed by usize, so if you're on a 64-bit machine, then you shouldn't need a cast. It's _unconstrained_ numbers that default to i32, not anything without a suffix.
- zerofan 10y ago> How would you have gone about making Strings be "as comfortable as integers"? I would prefer a str be a str be a str, regardless of how you got it. Lowercase type-name and fundamental like an integer. I'm fairly certain I understand why Rust made the choice they did. I've read the forum threads at HN, Reddit, and users.rust-lang, and I've seen previous replies by you and other Rusties, so I hope you won't try to educate me about the performance advantages of having slices as references and another string type as an ownership class or why we need OsStr and friends. If strings are the fundamental processing concern in your application, then I think you should be able to opt-in to that kind of micro-optimization and complexity, but it would've been better to spare the rest of us who have different concerns. I don't want to become a string expert to build a filename, and the default implementation could (at least conceptually) be always on the heap for all I care. Go one step further and implement the "small string optimization" (Alexandrescu's fbstring), and you'd probably get back most of the performance without nearly the complexity. > Arrays are indexed by usize I've spent the last half hour trying to troubleshoot why this line hangs: let aa = vec![1u8; 10e9 as usize]; However, I'm at home using the Ubuntu under Windows thing, so maybe there's some bad mojo between Rust and my less than usual setup. (If you're interested, I have 32 Gigs of memory, and the equivalent C malloc and memset code runs just fine, so I don't think Rust is doing the right thing here...). Anyways, I wanted to test the commented out line, but I'm stuck for now. If that line would work, I'll admit I was wrong, but I think the uncommented line shows a similar complaint. for ss in 0..63 { //print!("{}\n", aa[1<<ss]); print!("{}\n", 1<<ss); } > It's _unconstrained_ numbers that default to i32, not anything without a suffix. Looking at the present and the future, why is that a sensible default? Both x64 and ARM are going to use a 64 bit integer register for the operations, and many of those operations are going to be 1-clock throughput. You can probably find a counter example, but 32 bit integers aren't generally faster than 64 bit ones.
- mmstick 10y ago> Rust had the chance to make strings feel as comfortable as integers, but instead they introduced their own dichotomy with String and &str. It makes perfect sense when you understand the differences and reasoning behind it. A `String` is a heap-allocated string that can grow in size. On the other hand, a `str` is basically a fixed-size string array, but you'll never interact directly with this type because there's no point in it. It's tucked away inside the `String` that created it. Meanwhile, an `&str` is a slice of that fixed-size `str` array that's hidden within the `String`. You can think of a `str` as an `[char]` with it's own special `str` methods, and an `&str` as an `&[char]` which has access to all of the `str` methods as well. > Speaking of integers, Rust's choice of 32 bit integers as the default for literals is painful given that every machine most of us will ever care about is now 64 bit. I routinely deal with arrays and files that are too large for a 32 bit integer. I'm pretty sure the default integer is a `usize`, which is 32-bit on 32-bit systems and 64-bit on 64-bit systems.
- Manishearth 10y agoNo, the default integer is u32. If type inference can't provide a better type, Rust will pick u32. If type inference can pick a better type it will use it. So if you create an unsuffixed int literal and use it for indexing, that literal will be a usize. Rust will type error if you try to use u32s with an array so it's all good though. Just means that you need to specifically `: usize` things. If you need an integer type for counting stuff, u32 is fine. If you actually need to talk about memory, use usize. The compiler will force you to do it.
- mmstick 10y agoThat makes sense. I've never noticed what the default size was, but because it always worked with indexing, I assumed that it was always usize.
- Manishearth 10y agoI believe it used to be uint (usize) back in pre-1.0, and IIRC inference didn't work well or wasn't supposed to work at all. I recall needing explicit prefixes on my int literals back then. No longer the case.
- duneroadrunner 10y ago> and so I'm stuck with C++ If you're stuck with C++, might as well do it safely: (shameless plug) https://github.com/duneroadrunner/SaferCPlusPlus https://github.com/duneroadrunner/SaferCPlusPlus
- zerofan 10y agoI looked briefly at your code. I don't believe it is possible to be compatible with the STL and safe in the way the Rust guys intend. I might be wrong though. What happens with your vector in this code? using namespace mse::mstd; vector<double> data(10); double& dangling = data[0]; data.resize(100000); double crashing = dangling; You use a lot of typedefs, so I couldn't tell for sure, but I think your operator[] returns a C++ reference right? The problem here is there is only one operator[] for both reading and writing. This is a simple contrived example, and taking a reference like that looks artificial, but there are a lot of other ways in real programs to stumble on to this. (I don't think it's as bad as the Rusties do, but I stumble into this bug once or twice a year...) The Rust folks seem to believe you need a borrow checker to solve this problem, but I think that a different container library in C++ could do the trick. For instance, favoring value copies instead of references, and returning a proxy object from operator[] instead of a reference.
- duneroadrunner 10y agoNative C++ references are technically unsafe, so code that uses them would not qualify as "strict" SaferCPlusPlus code. In the case of your example, the "double&" is technically not kosher. The easiest way to make it safe would probably be to use a (safe) iterator instead of a native reference. So instead of double& dangling = data[0]; you could make it auto not_dangling_iter = data.begin(); // not_dangling_iter += 0; C++ references are the one unsafe element that does not have a "compatible" safe replacement. Unfortunately, you have to convert your references to pointers (or iterators). I don't think there is a way to create a "safe" reference with an interface compatible with native references. Apparently C++ will at some point add the ability to overload the dot operator, but I'm not sure that will be enough to be able to emulate C++ references. And while I can overload the & (address of) operator to "prevent" you from getting a native pointer to a "safe" object, I don't know if there's a way to prevent you from getting a native reference. If you wanted to somehow enforce a prohibition on the use of unsafe C++ elements (like references), that would probably require some sort of static tool that is not yet available. But should be fairly straightforward to implement, I think. But if you just want some confidence in the safety of the code you write, it doesn't take much effort to reliably avoid using C++'s unsafe elements.