Live data from Hacker News

My Struggles with Rust

compileandrun.com

201–210 of 329 posts

Re: My Struggles with Rust

#201
post #44

Earlier quoted context omitted.

There are many ways to have both enforced error handling AND less boilerplate. Java's checked exceptions are much maligned but would work very well here. Another way would be having more syntactic sugar for Result-style monadic error handling, like the do notation in Haskell or for..yield in Scala. Another issue raised by the original post is the fact that Rust has no top-level concrete error type that is convertible…

Java's checked exceptions were a disaster. It essentially handcuffed you, limiting what you could do in an overridden method (because you can't add more exceptions to the throws list). So you end up wrapping in RuntimeExceptions and then later having the whole app fall over because the framework that's expecting your class was only designed to handle the checked exceptions. So yeah, want your implementation to consul…

> interface you must implement doesn't declare any checked exceptions

It verges on malpractice to design an interface and declare that no implementation of it could possibly ever fail. I'm looking at you, Runnable.

Re: My Struggles with Rust

#202

Earlier quoted context omitted.

I think that part of it is that the idea of a Result type being normal will help prevent much of the cruft and burying we see with exceptions. I also feel like handling Result types is more natural than exceptions. First, you _have_ to do it, even if that means a try! and passing the buck. The syntax for this isn't as monstrous as it is for checked exceptions as well. Second, it feels more like a natural code-flow, n…

You don't have to convince me of the value of Result types, I prefer them too. I've only written a couple thousands of lines of Rust but tens of thousands of Haskell which rely on the same concepts (though its nicer with do notation). I don't have faith in the masses though and right now there is a strong selection bias in Rust that means only people concerned with quality and correctness are using it in the first pl…

> I think twenty-five years ago there were similar hopes and dreams for Java checked exceptions.

Yeaaaaaaah. I remember being a very strong supporter of checked exceptions before I got into a giant codebase and saw how not having speced a sane exception type can cause lots of pain and some really long declarations or dropped exceptions.

   catch (Exception e) { throw new RuntimeError(e); } 
:(

You're right, I guess time will tell.

Re: My Struggles with Rust

#203
post #188

Earlier quoted context omitted.

I would love a `#[derive(From)]` for newtype structs and enum variants. Would bring Rust error handling back below Java in boilerplate levels. :)

There are some crates that add a derive for errors, but most people tend to use error-chain or quick-error. Both give you the boilerplate pretty much for free, with various other advantages. E.g., using error-chain, you can just write the above code as error_chain! { foreign_links { Io(io::Error); Parse(ParseIntError); } } and it'll even generate an aliased `Result` type as well as fancy chaining support.

Right- error_chain is just a bit too much magic for me compared to what #[derive(From)] would do.

Re: My Struggles with Rust

#204

Earlier quoted context omitted.

I can't speak for Go, but what you describe isn't really a thing in Rust. Functions in Rust that might encounter an "exception" typically return something like `Result ` where `T` is the type of what we hope we get and `E` is a type that encodes the details of the errors/exceptions we might see. It's an enum type that comes in two flavors: `Ok(T)` and `Err(E)`. You can't just go happily along treating an `E` like it'…

Good point. I am not very familiar with Rust (good to hear it seems to treat this well, however!) but a cursory examination of Go code shows that runtime errors can end up being entirely ignored and that seems crazy to me. > I tend to be more interested in how the features of a language help programmers to keep writing correct and maintainable code as the complexity of a project grows. So let me guess, you too have w…

> but a cursory examination of Go code shows that runtime errors can end up being entirely ignored and that seems crazy to me.

I'm not sure whether this is a thing in Go, but I tend to think that having a ubiquitous null object in your language that's "falsey" is responsible for a lot of problems like what you describe and is basically a misfeature outside of C.

> So let me guess, you too have worked on very large spaghetti codebases? ;) Because I am also interested in that very same end-goal! And that is actually why I've decided to only focus on functional langs for now (right now it's Elixir but I'm going to be evaluating Haskell, not a huge fan of the JVM langs tho), because the resulting code just feels more maintainable

Sure have :). My personal opinion is that rich type systems like Haskell's (and Rust's, they are actually very similar in many ways) are really nice for managing complexity, maintaining and refactoring with confidence, and cutting off lazy design decisions at the roots. It takes a fair amount of experience (and I don't think I'm 100% of the way there yet by any means) to use them in a way that gets them out from under your feet and makes them really work for you, but it's experience worth having IMO.

Haskell is really great, IMO well worth learning even if you end up not using it professionally. Also, it's not built on the JVM; you might be thinking of Scala?

Re: My Struggles with Rust

#205

It makes me sad to see the example. This is why I maintain `.unwrap()` is one of the worst things in rust. ...because people use it; and then say; 'but don't use unwrap...'; and then use it, and your 'safe' language then happily crashes and burns everytime something goes wrong. Blogs and documentation are particularly prone to it. Result and option types are good; but if you're gonna have unwrap, you basically have t…

I agree, its not a great idea to use unwrap() in production code, it is bad even when its safe to unwrap.

But speaking about blogs... Why not to use .unwrap() there? Its simple, and allows to show some ideas without digging into error handling, just point to places where those handling should be placed.

> but if you're gonna have unwrap, you basically have to have exceptions as well (or some kind of panic recovery) ...

https://doc.rust-lang.org/1.9.0/std/panic/fn.catch_unwind.ht...

Re: My Struggles with Rust

#206

Earlier quoted context omitted.

How is this problem solved for C++?

The nice thing about C++ is that it is so widely used that for just about any task you can find examples of how to do it (usually many different ways to do something), especially for tasks like this article. You will also find plenty of C example, which you could also use in C++.

Unfortunately 90% of them will be outdated/wrong/unsafe. Being backward compatible with 30 years of code means you're unlikely to find the right answer for the present. And worse, you won't know it.

Re: My Struggles with Rust

#207
post #164

Earlier quoted context omitted.

Exceptions actually can need RTTI, though not necessarily all of the RTTI that things like provide. For some details, see the -fno-rtti flag for GCC, for which the documentation says[1]: Disable generation of information about every class with virtual functions for use by the C++ runtime type identification features (`dynamic_cast' and `typeid'). [...] Note that exception handling uses the same information, but it wi…

That is a compiler specific implementation, the ANSI C++ standard doesn't require it.

That's great and all but when every modern compiler does implement it that way it's not something you can ignore.

Show me a compiler that's used in production which handles multi-inheritance exceptions without allocating extra data and I'll be happy to eat my words :).

Re: My Struggles with Rust

#208

Earlier quoted context omitted.

The nice thing about C++ is that it is so widely used that for just about any task you can find examples of how to do it (usually many different ways to do something), especially for tasks like this article. You will also find plenty of C example, which you could also use in C++.

Unfortunately 90% of them will be outdated/wrong/unsafe. Being backward compatible with 30 years of code means you're unlikely to find the right answer for the present. And worse, you won't know it.

You base your 90% claim based on what? I have entirely different experience and I am using C++14 and C. K&R "C programming language" is from 1978 and it's still one of the best books about C still used in 2017. I see many stackoverflow answers updated from C++98 to C++11/14 and some even to C++17.

Re: My Struggles with Rust

#209
post #164

Earlier quoted context omitted.

That is a compiler specific implementation, the ANSI C++ standard doesn't require it.

That's great and all but when every modern compiler does implement it that way it's not something you can ignore. Show me a compiler that's used in production which handles multi-inheritance exceptions without allocating extra data and I'll be happy to eat my words :).

Sadly I cannot pay for all commercial compilers out of my own pocket. :)

Re: My Struggles with Rust

#210
post #4

My main gripe with Rust so far has been the unnecessary profusion of Result types, making it hard to process and forward errors. Case in point: the example in the article from the rust documentation that converts errors to strings just to forward them: https://doc.rust-lang.org/book/error-handling.html#the-limit... In practice, I find a type like Google's util::StatusOr ( https://github.com/google/lmctfy/blob/master/…

I think having Result alone does not make error handling complicated, but having different error types for each operation (and concrete result) instead of using one generic error type for all of them does by pushing the job of unifying erros towards the user. Go works around the problem by Error being an interface, which means any function can return any kind of error without needing to transform it to another form.…

> instead of using one generic error type for all of them

But you can do that in Rust, just use Box. No library does that though, because it is not a zero-cost abstraction.

Post reply on HN