4 ms·
Once I got used to writing in Rust, I found it really hard to mess up. I sort of like it for applications, although some idioms can be a bit verbose and hard t
by rectang 5y ago
Once I got used to writing in Rust, I found it really hard to mess up. I sort of like it for applications, although some idioms can be a bit verbose and hard to parse visually and mentally.
First, thanks to default immutability of variables and the borrow checker, I trust that I'm far less likely to accidentally mutate something and cause an action-at-a-distance bug.
Second, I absolutely love idiomatic Rust error handling of returning a Result (especially combined with the question-mark operator). It forces me to deal with error conditions. Unlike C# or Python or Java or C++, I don't have to worry that any code could throw an exception at any time. (Rust code can panic, but panics generally represent unrecoverable errors — see http://joeduffyblog.com/2016/02/07/the-error-model/#bugs-arent-recoverable-errors http://joeduffyblog.com/2016/02/07/the-error-model/#bugs-are... ) And unlike Go or C, I don't have to remember to check the error every single time.
I still have to write functionality tests for Rust code, but once I've done that I feel like the code is mostly locked down. It's harder to get to that sense of security in other languages.
- mikece 5y ago> "Once I got used to writing in Rust..." How long did that take and what resources did you use to learn?
- rectang 5y agoI started off with standard materials like "Rust By Example". I also tried to use Rust for simple stuff like command line utilities. Then I started working on a personal project, which motivated me to bull through lots of difficult problems. (This personal project happens to have been bindings for Apple Core Audio, but the point is to pick something you care about enough to motivate yourself.) Finally, I've found users.rust-lang.org invaluable. The first major challenge for me was the error handling ("WTF is `Box<dyn std::error::Error>`? What is `Box`? What is `dyn`?"). It got in the way as soon as I even tried to write command line utilities. Once you learn it, it's amazing, but out of the gate I continually stumbled and fell flat on my face. The second challenge was harder: coming from OOP languages, I was accustomed to structuring everything as large mutable heap-allocated classes with private fields, accessors, and an emphasis on opaque data structures and encapsulation. That is not idiomatic Rust, so I had to unlearn it and discover architectural alternatives. I don't know exactly how long it took before I felt comfortable, since I was learning in disconnected spurts rather than immersively all at once. It wasn't quick, though.
- jcelerier 5y ago> Unlike C# or Python or Java or C++, I don't have to worry that any code could throw an exception at any time. (Rust code can panic, but panics generally represent unrecoverable errors — see http://joeduffyblog.com/2016/02/07/the-error-model/#bugs-are http://joeduffyblog.com/2016/02/07/the-error-model/#bugs-are... ) I just don't understand this logic. Exceptions are the same (C++ exceptions use the very same unwinding mechanism than panics in Rust as far as I can see), why would you forbid yourself to catch_unwind ? It's just making your software worse for no reason, users always will be happier with an app that shows a small "warning: internal error. Document backup saved in </some/place/>. $software will now shutdown", than seeing macOS or Windows's crash dialog.
- rectang 5y agoFor application code, you can change the behavior of Rust panics. Although I haven't verified this myself, I fully expect that you can achieve saving a document and exiting gracefully. The distinction is that panicking should (almost) never be used for recoverable errors. You can, but that's not idiomatic and would only be appropriate within the confines of your own application. Recoverable errors in Rust should be handled by return values, typically via either Result or Option. This is unlike all the other options I listed (except Go, and C++ with exceptions disabled), where it is idiomatic to use exceptions to handle recoverable errors. In theory, (strictly) checked exceptions are equivalent (isomorphic) to error codes as an error handling mechanism. But as soon as unchecked exceptions are allowed, it all falls apart and you must contend with the problem of "invisible control flow". Not having to deal with "invisible control flow" in Rust is one of the things that makes me much more confident that the code actually does what it looks like it does. The Joe Duffy blog post I linked to earlier compares various error handling methods, including checked exceptions. It's very long, but interacting deeply with this blog post helped me to level up my understanding of error handling. FWIW I did a presentation on Duffy's article for the San Diego chapter of Papers We Love: https://www.youtube.com/watch?v=GwPBC4mWfFQ https://www.youtube.com/watch?v=GwPBC4mWfFQ
- jcelerier 5y ago> You can, but that's not idiomatic I know that this is a fairly contrarian take, but I strongly believe than the emphasis on idiomatism is more harm than good. The only thing that matters is the language spec - everything that fits in there is kosher. Idioms just create pointless fights and tabs vs spaces situations where there doesn't need to be any. > Not having to deal with "invisible control flow" in Rust is one of the things that makes me much more confident that the code actually does what it looks like it does. no, you just choose to ignore it. I can also write C++ code with throw and no try..catch and that will give the same result (as I pretty much use exceptions like one would use panic! in rust). I don't know anyone who would say that this is a good idea. My sweet spot is to have a few catch handlers around the main loop which catch 99% of the unrecoverable issues, and sometimes, when it turns out that an issue has a way to be recovered (or that maybe it doesn't matter), then someone gets a try..catch block. Like most articles about exceptions, that Joe Duffy post talks about the problem of "where the control flow goes". I've written my first lines of C++ something like 17-18 years ago now and not once it has actually been an issue. Consultants sure do love selling it as one though.
- ViViDboarder 5y ago> And unlike Go or C, I don't have to remember to check the error every single time. How do you mean? I’ve been writing Rust frequently lately and you still have to check the case. Do you mean that the compiler will nag you if you stunt so you don’t have to remember to do it because you’ll be reminded? That’s one of the things common Go linters do that I wish was built into the compiler. It’s silly that an unused dependency is a compiler error but an unchecked error/return value is not.
- rectang 5y agoI mean that in Rust, you have to work kinda hard to drop an error on the floor and leave it unhandled. It's easy and idiomatic to write code which calls `unwrap`, so that's what everybody does when they don't want or need to write sophisticated error handling code. But that's not the same as forgetting to check a return value — when something goes wrong, `unwrap` panics. I mean, if you're determined you can definitely drop an error in Rust, e.g. with a `match` arm that does nothing. But the easy path is to `unwrap`.
- JeremyNT 5y agoI learned rust before go and I was shocked by the (lack of) error handling in go. unwrap feels lazy, but it's obvious what is doing and it's impossible to do nothing. With go error handling is entirely optional.