Hacker News new | ask | show | jobs
by hammerdr 3956 days ago
Warning: very little knowledge of Rust and Iron

Can someone explain why there is an extra Ok(...) in this? (I want to call it a function, but I'm not even familiar enough with Rust to be sure that it is a function).

Is it something that could be removed? Right now it just looks like boilerplate.

Edit: Thanks everyone! Ok is similar to a Right or Success of a Either/Result type of object.

4 comments

You mean in the handler? The return value has to be of a type `IronResult<Response>`. That means it can be either `Ok(...)` for success or `Err(...)` for failure.

In other languages/frameworks (python/pecan for example) you'd throw an exception in case of things going wrong. In Rust exceptions are for very exceptional things only (it's called panic). So the more calm way is just to return `Err(...)`.

It's not a function, it's more like a tagged union (in rust called an enum). So in practice it's like C's union, but you do know which member was chosen and only that one is accessible.

Small correction: Rust doesn't have exceptions. panic!() crashes the current thread with an optional error message, but it doesn't do stack traces and there's no try/catch in the language (there's the try!() macro, but it works with Result<T, E> values, has nothing to do with panics).
It records stack traces. Use the environment variable `RUST_BACKTRACE=1` to print them.
I assume you mean in the example at the top of the page.

In theory, a view function should just take a request object and return a response object that encodes 200 OK if all went well, and something wilder like 404 Not Found or 500 Internal Server Error if something goes awry. In practice, problems can happen at a much lower level than HTTP error codes are designed to handle, like "database connection refused" or "template file not found".

Rust's general-purpose error-handling system is the Result<T, E> type, where T is some useful return type, and E is some type representing an error. A function that does error-handling is declared as returning, say, Result<String, MyError>, and then in the body of the function you can "return Ok(somestring)" or "return Err(someerror)".

I see that the example function returns an instance of type IronResult<Response>, which I assume is a wrapper around Result<T, E> that hard-codes E to be some Iron-specific error type (in the same way that Rust's std::io::Result<T> is shorthand for Result<T, std::io::Error>), so the Ok() is telling the framework "this is an actual legitimate response you should send to the browser", as opposed to an excuse for not producing a response.

Because hello_world returns an IronResult, which in turn is just a simple Result type from Rust. Note that the status::Ok is different from the Ok(...).

Iron::new expects a function that returns a Result type, so it has to be there.

Also, because it is a Result it forces the caller to either handle the error or explicitly panic on it, right? They can't ignore it? (which is awesome!)
Yes, because it is a Result, the caller cannot access the success value without acknowledging the existence of an error -- via match , unwrap, or try.

If the caller does not want to use the success value (esp. in cases which return Result<(),E>, i.e. return an optional error), there is a lint which tries to ensure that the error value is handled, though as steve says you can circumvent it (which is done in an explicit way so that it's pretty obvious that there is an error being ignored).

They could do something like

    let _ = something_returning_result()
But without the let, there's a warning. And culturally speaking, let _ is discouraged for this reason. If I want to ignore an error condition, I unwrap() instead, so at least my dumb decision will blow up in my face later instead of faint silently.
I think they were talking about the compiler-enforced exhaustive match, not must_use.

The fact that you must acknowledge the existence of the error value before accessing the meaty success value (either with a match, an unwrap, or a try) is a great feature in Rust.

must_use forcing you to handle errors for things you don't need the meaty success value of is just icing on the cake.

It is needed because the handler doesn't return a Response, it returns a Result that wraps a Response if there isn't an error. This provides the means of error handling.