Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Interesting! I don’t know how modern C++ deals with multi threading and shared memory etc.? Care to fill us in on the state of the art and how it’s as good as rust?


State of the art is pthreads and mutexes. The C++ and Rust wrappers for them are roughly equivalent.

Rust has some nice features for handling ownership semantics, but they are not significantly better than those in C++.

Meanwhile, Rust still lacks a normal exception handling story. Exception handling is absolutely necessary in 2018 for building real software systems.

(And even though Rust claims that errors are nicely dichotomized into "recoverable" and "not recoverable" camps, this is simply not true in the real world. There are obvious counterexamples that don't fit into this dichotomy.)


Haven't spent that much time with rust, but so far Result<> has sufficed for all my exception-needs; it's not clear to me what the practical difference is between exceptions and result<>, that would be relevant to implementing real software systems?

As I understand it, the primary usage of both is to report, and handle, errors. Rust splits it as panic! and Result<>, where panic! is naturally left for logic errors (ie states the program should never reach, regardless of circumstance; maintaining invariants), and Result<> is for everything else.

Exceptions do the same, but you can catch the broken-invariant case as well? I'm not sure how often you want to recover from such a state though.

Another aspect is retrieving the stack-trace, which iirc doesn’t exist in a normal result-type, but error-chain! magically handles it for my case (never looked into how, or at what cost)

Otherwise, the other major difference is that rust enforces that you explicitly handle all result types, making it part of the API contract, while most languages, with unchecked exceptions, leave it as a new runtime error to be found after updating your libraries. Java gives you checked exceptions, but in a much more syntax-unpleasant fashion (but thats always the case with java).

As far as I'm aware, Result<> seems to me a much cleaner solution than exceptions for the same use-case. A bit of concern for API updating, since the errors are part of the API so its more difficult, but at the same time, I'd rather update the library and fix the codebase, than update and wonder if a new Exception exists (or perhaps, always existed? Is there any way to find out the list of possible exceptions in C++, without reading the function, and all the code it depends on?).

The primary unpleasantness is that a single use of Result<> infects the entire callgraph until its handled, but thats true with exceptions as well. I'm not too happy about async/await for the same reason

Of course, part of the reason I'm interested in using rust as my hobby-language is because I'm absolutely sick of runtime errors and writing worthless tests in python, so maybe there's an appeal thats missing for me


> I'm not sure how often you want to recover from such a state though.

Pretty much always in real systems software.

Imagine a multithreaded server that handles HTTP requests. A catastrophic invariant failure when handling one requests shouldn't bring down the whole server.

Or imagine an application that calls into a money transaction routine. (This routine can itself call other routines, and so on for 12 stack frames deep.) A catastrophic failure in sending money shouldn't bring down the whole app, it should show a clean "money transfer failed, please try again" message.


When I'm talking about invariants, I mean something much more fundamental than a web-request failing. It's not a necessarily invalid state (and I'm not sure ever should be for any well-behaved program). It would be invalid if you've explicitly decided not to handle the scenario, but at least in Rust (and assuming the function properly returns Result<>), you can't forget to not handle it.

Essentially where you'd have asserts() in C. eg Your in-place sort function is meant to maintain a sorted list for all elements traversed so far: you add a panic check to guarantee this. It fails; the invariant is broken, and there's no recovering from such a state (your sort is not sorting! you're going to add a handler for this..?).

A web-request failing is a simple, normal, expected failure (hence the Result<> type). Adding 1+1 and getting 3 is a broken invariant, and there's no coming back from it. Again, you can (probably) catch it in Java since it throws exceptions on anything and everything... but why would you want to? If you take its to its conclusion, you're not trusting any aspect of the language anymore: you'll have to check every bit of code for arbitrary outcomes.

It seems to me similar to javascript allowing you to basically pass in anything to everything and get ...some... output, but its an extremely bug-prone methodology.

panic! is, afaik, intended for those situations where it should bring down the whole application (before you start adding $3 to person A, but subtracting $2 from person B); primarily to catch programmer errors, not execution errors. Errors that can be recovered from are Result<>, and the Result<> type forces you to handle all possible outcomes (which the caller might decide is a panic!). A failed web-request is most certainly a Result<> in this model, not a panic!.


That's why you would return a Result from all those and handle any failures that way. The Result type is meant to be used any time an operation could fail.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: