6 ms·
Three problems with this: 1. You still have to fight with borrow checking in Rust as in C++, it’s just not automated. You have to consider moves and copies, bo
by ilovecaching 8y ago
Three problems with this:
1. You still have to fight with borrow checking in Rust as in C++, it’s just not automated. You have to consider moves and copies, borrowed references, etc. As the author points out, if you’re used to writing C or C++, it’s going to take a while before responding to the borrow checker is second nature. The point is that the borrow checker is a computer and doesn’t make mistakes the same way a human does, and that’s value added not detracted.
2. Having the benifit of actually having a package manager, Rust is much easier to download and use dependencies with. That said, I agree with the general premise of not using Rust if you have an immediate business need and it’s missing a core library. My issue is that it should be fairly apparent before you start a project what dependencies you need, so a rewrite back to C++ seems odd. Also, Rust is an open source ecosystem, and people using it should feel compelled to consider writing the missing pieces they need for the benifit of the community. It’s also odd to say that Rust doesn’t have what you need, it sounds like there are C libraries that already do what you want, and Rust can wrap C.
3. If something is written in C and you don’t have time to replace it, just wrap it in unsafe and make a safe interface over it. Rust is exceedingly good at interfacing with C, so any library you can use in C can potentially be used in Rust.
- mrfredward 8y ago>You still have to fight with borrow checking in Rust as in C++, it’s just not automated. It's not that easy. The borrow checker gives you memory safety and thread-safety. In C++, you always have to worry about memory safety, so here the ownership model and borrow checker is a pure win. However, in C++ you don't have to worry about thread safety in a single thread...there's no barrier to passing pointers around and mutating things from different places in your code. In rust, the borrowchecker disallows shared mutable state...that's a huge win if you want to parallelize your code later on, but it also means that things that are trivial in C++ take a lot of thought and effort in rust, especially if you're thinking in a C++ paradigm (as opposed to coming from a functional language).
- shepmaster 8y agoMy counter argument is nicely summed up by The Problem With Single-threaded Shared Mutability (https://manishearth.github.io/blog/2015/05/17/the-problem-with-shared-mutability/ https://manishearth.github.io/blog/2015/05/17/the-problem-wi...)
- mrfredward 8y agoI like the blog post, and I mostly agree with you that shared mutability can cause problems in big programs. It's something I try to keep to a minimum in most code I write, and I'm better at avoiding it after learning rust. The thing is, getting rid of shared mutable state entirely is a huge paradigm shift. It means many libraries (GUI libs especially) can't be cleanly wrapped. It means throwing away common data structures like linked-lists. A C++ programmer can learn the syntax of rust is a week, but it may take years to get comfortable with the borrow checker.
- duneroadrunner 8y agoYes, It's hard to deny the intuitive appeal, but what's notably missing from that blog post, and seemingly any other article about it, is a consideration of the cost/downsides of universal imposition of the "exclusivity of mutable references" restriction. Rust provides the RefCell wrapper to essentially circumvent the restriction on demand, but i) that also essentially circumvents the "invariant protection" benefits of the policy, and ii) you can just as easily use an equivalent wrapper[1] in C++ to impose the same restriction. At which point the difference between Rust and C++ just kind of becomes which policy do you want to be the zero-overhead default. I mean you could imagine a hypothetical future scenario where it is demonstrated that the optimizers are good enough to essentially eliminate the run-time cost of RefCell wrappers, and a lot of Rust programmers just start wrapping everything with RefCells by default. [1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus#exclusive-writer-objects https://github.com/duneroadrunner/SaferCPlusPlus#exclusive-w...
- shepmaster 8y ago> Rust provides the RefCell wrapper There is also `Cell` (https://doc.rust-lang.org/std/cell/struct.Cell.html https://doc.rust-lang.org/std/cell/struct.Cell.html), which offers a different set of tradeoffs. > which policy do you want to be the zero-overhead default The one where: - The compiler can make more optimizations - I'm less likely to shoot myself in the foot my conflicting mutations is a good default for me, so I'm in favor of Rust. > a hypothetical future scenario where it is demonstrated that the optimizers are good enough This sounds like the sufficiently smart compiler (http://wiki.c2.com/?SufficientlySmartCompiler http://wiki.c2.com/?SufficientlySmartCompiler) argument. While I'd love to live in this world, we aren't there yet. Even in such a world, there would still be reasons to choose Rust over C, such as standardized dependency management or a rich type system.
- htfy96 8y agoAnother issue is that in real world types in fast programs usually can't be expressed and auto checked by a simple type system without mental/runtime overhead. For example, in many GPU kernels each thread visits patterns like (ax+b)%k, how do you ensure no data race in this example? The result depends on the coprimality between a and k. You will still need to check this at runtime and creating affine_mod_view for each access patterns like this would be overkill.
- epage 8y ago> As the author points out, if you’re used to writing C or C++, it’s going to take a while before responding to the borrow checker is second nature I see these comments and it feels so foreign to my experience. The borrow checker was second nature to me because of my C++ experience. These were things I already had to juggle mentally. On rare occasions, it complained about something that I could prove was valid but I understood why it couldn't tell. Usually, when I hit it, it is because I forgot a case and am grateful for it. I know of at least one optimization I've made that I would never have bothered with without the borrow checker. It would have been too much bother for me to reason about everything. Even if I did, it would have been even worse to maintain.
- rcxdude 8y agoI think it depends on your level of C++ experience. Very experienced and effective C++ developers often will have internalized a lot of the rules of the borrow checker, possibly without consciously realising it. Less experienced developers will not have run into the problems caused by not following these rules because a lot of the time you can get away with it, and/or they haven't associated these habits with the bugs they tend to cause. It's a fairly common theme for people who have learnt rust to report that it has made them a better C++ developer.
- ilovecaching 8y agoPersonally, I had the same experience as you did, except the borrow checker also helped me unlearn a few bad habits and gave me a deeper understanding of references. Now it is second nature, and I rarely every fight the borrow checker. I think part of it is planning ahead.
- pjmlp 8y agoWere you trying to write GUI code? Because of my experience it was also plain sailing, while doing the tutorials and exercises from the books I bought. Then I tried to make a GUI application in Gtk-rs and had lots of fun with event handler callbacks, which are the main reason why Relm was created.
- 8y ago
- SamuelAdams 8y ago> Also, Rust is an open source ecosystem, and people using it should feel compelled to consider writing the missing pieces they need for the benifit of the community. It’s also odd to say that Rust doesn’t have what you need, it sounds like there are C libraries that already do what you want, and Rust can wrap C. This sounds like a great idea, but not everyone has the time and resources to port libraries from one language to another. It should be trivial to wrap C libraries, but errors do show up, and a once one day task now takes a week to iron out. If you have 4 or 5 libraries that are missing, you've now lost a month of development work that could have been spent adding new features. Additionally, not everyone wants to maintain open source projects. There's a huge amount of responsibility that comes with being a maintainer, and the OSS community isn't always a friendly, fun place. Rachel has some great examples in her blog [1]. [1]: https://rachelbythebay.com/w/2018/10/09/moat/ https://rachelbythebay.com/w/2018/10/09/moat/
- IshKebab 8y ago> You still have to fight with borrow checking in Rust as in C++, it’s just not automated. This is so misleading. Sure you still have to think about borrowing in C++ but in C++ you only have to convince yourself that you got it right. You don't have to convince a dumb child that barely understands variable scopes. The benefit is of course that the dumb child is 100% reliable so if you can convince him then you are 100% sure you got it right... But please can we stop pretending that it isn't a massive pain in the arse to convince the borrow checker that your code is ok. Also as someone else pointed out, if you are only writing single threaded code the mutable borrowing rules are needlessly restrictive. I like Rust but it really irks me when people pretend it is as easy as C++. It isn't. It is much harder - it's just that when you're done you have (probably) a better result.
- jamwt 8y ago> I like Rust but it really irks me when people pretend it is as easy as C++. It isn't. It is much harder No it's not. "hard" is not single dimensional. "hard" to write your first hello world? No, both are easy. "harder" to write your first moderately-sized program that basically works? Yes, for almost everyone. You'll fight the borrow checker. The learning curve is real. "harder" to write your first large/medium, correct program? Definitely not. The safety will save you, here. It's not just memory. It's no nulls, it's no exceptions, pattern matching exhaustion enforcement, baton-passing session type patterns, race-freedom, and so on. The "it compiles, it works" dynamic is akin to OCaml/SML, if you've used those at all. Except it's even better because you get prompt resource finalization. "harder" to write your nth program after ~6 months of usage? Not by a long shot. Rust is actually an incredibly expressive language. Once you learn to shape code the way the language expects, you'd be shocked at how productive you are. It's in the same ballpark as go, perhaps a little better if you're doing something nontrivial due to the power of generic libraries. I spend almost no time "fighting" the borrow checker, as do most ramped-up Rust programmers. It's pretty much all win at this point. It's a different category of language than C(++). It actually gets a little exhausting hearing people talk about how hard the borrow checker when folks have barely used the language. These days, the only time I'll use a GC is if I'm writing something _very_ fast and short in Python. An experiment, a prototype, or a tool. A short REPL session. I really do not miss GCs otherwise. But yes, compile times are somewhat slow. If you go template crazy in C++, you'll be in the same ballpark. But the "equivalent" C codebase will smoke it.