Rust has many container-like objects that may or may contain a value, like Box. Most of these have an unwrap() method that either obtains the inner value or panics the whole application.
Box is a bad example; it always has a value and can’t be unwrapped. It’s Result<T> and Option<T> that are the primary wrappers.
Result is for Errors, and Option is for nullables. If you consider it that way, the “issues” with unwrap are identical to other languages when errors and nulls aren’t properly handled.
It’s the abort that is the crux of the issue here. Usually you would either pass the std::optional up/down the call stack. If you don’t control the types (e.g. using a library or a framework) you’d come up with some “default” value instead, like this:
But sometimes there’s no good “default” value, and then you have to resort to just unwrap-ing the value, and accepting that the program will abort when that function call fails. Usually this is a sign of poor engineering somewhere, likely in a library you’re using, and should be fixed; but sometimes you don’t have the time to fix it, and then it ends up in production.
It’s more like a method that can throw an exception. Rust doesn’t really have exceptions, but if you have a Result<T> or Option<T> type you can Unwrap it to get just the T. But if there’s no T to get (in the case of an Error type for Result for None for Option) the call panics.
In some cases unwrap could be useful if you don’t care about a panic or if you know the value can’t be None. Sometimes it’s just used as a shortcut. You can likewise do this in C#:
A panic isn’t the same as an exception though, you can’t ‘catch’ a panic, it’s unrecoverable and the program will terminate more-or-less immediately.
Rust provides a generic type Result<T, E>, T being a successful result and E being some error type, which you are encouraged to use along with pattern matching to make sure all cases are handled.
Rust does not have exceptions. You never have to try/catch. Functions usually encode the possible failures in their types, so you’d have something like this C++ snippet:
And then the caller of downloadFile has to decide what to do if it returns an error:
autores=downloadFile(url);std::visit(overloaded{[](FileDownloadErrore){/* ignore error, or handle it somehow */},[](std::filesystem::pathp){/* do something with the path we downloaded */}},res);
However, Rust makes this whole thing a lot easier, by providing syntax sugar, and there are helper libraries that reduce the boilerplate. You usually end up with something like
(notice the #[from], which forwards the error message etc from the std::io::Error type)
And the consumer code is something like this:
letres:Path=download_file(url).unwrap_or_else(|e|{/* Ignore the error or handle it. You have to return a new path here */});/* res is guaranteed to be a valid Path, you don't have to care about errors from download_file anymore */
Or
letres:Path=download_file(url)?;/* res is guaranteed to be a valid Path, you don't have to care about errors from download_file anymore */
Which will just forward the error to your caller (but your function has to return Result as well), or proceed with the execution if the function succeeded.
Finally, download_file(url).unwrap() is if you can neither ignore nor handle the error. It will abort if the function fails in any way, and there’s no (practical) way to catch that abort.
It’s worse than that. In C++, if you fail to catch an exception, then std::terminate() is called. In Rust the only options are roughly equivalent to C++ noexcept, or std::terminate() [panic in Rust]. There’s nothing in between.
i’ve been meaning to get into rust; but i’m learning that i lack motivation if it’s not part of my job and becoming a sysadmin again doesn’t require it.
Thank you for the easier captchas, and pre-emptively damn you for whatever evil thing CloudFlare will eventually do with their MITM access to everything.
can you explain the joke, i work at cloudflare
Rust has many container-like objects that may or may contain a value, like Box. Most of these have an unwrap() method that either obtains the inner value or panics the whole application.
Box is a bad example; it always has a value and can’t be unwrapped. It’s Result<T> and Option<T> that are the primary wrappers.
Result is for Errors, and Option is for nullables. If you consider it that way, the “issues” with unwrap are identical to other languages when errors and nulls aren’t properly handled.
I reckon the person you’re replying to knows exactly what unwrap is, because the last big famous Cloudflare outage was caused by it. They were making a joke of their own
sounds like an error handling issue
Yes it is. Typically you’d do some pattern matching to handle every possible case, but Unwrap is often used as a shortcut.
Whoosh
Is this just like the equivalent of a getter method in C++?
It’s worse than just exceptions in C++. It’s a bit like this snippet:
It’s the
abortthat is the crux of the issue here. Usually you would either pass thestd::optionalup/down the call stack. If you don’t control the types (e.g. using a library or a framework) you’d come up with some “default” value instead, like this:Or in Rust:
But sometimes there’s no good “default” value, and then you have to resort to just
unwrap-ing the value, and accepting that the program will abort when that function call fails. Usually this is a sign of poor engineering somewhere, likely in a library you’re using, and should be fixed; but sometimes you don’t have the time to fix it, and then it ends up in production.It’s more like a method that can throw an exception. Rust doesn’t really have exceptions, but if you have a Result<T> or Option<T> type you can Unwrap it to get just the T. But if there’s no T to get (in the case of an Error type for Result for None for Option) the call panics.
so you have to wrap everything in a try/catch?
Not really, because rust doesn’t have exceptions. Instead you are encouraged to handle every possible case with pattern matching. For example:
Option<u8> is a type which can either be some 8bit unsigned integer, or none. It’s conceptually similar to a
Nullable<int>in C#.In C# you could correctly implement this like:
In rust, you can call Unwrap on an option to get the underlying value, but it will panic if the value is None (because None isn’t a u8):
In some cases unwrap could be useful if you don’t care about a panic or if you know the value can’t be
None. Sometimes it’s just used as a shortcut. You can likewise do this in C#:But this throws an exception if number is null.
A panic isn’t the same as an exception though, you can’t ‘catch’ a panic, it’s unrecoverable and the program will terminate more-or-less immediately.
Rust provides a generic type
Result<T, E>, T being a successful result and E being some error type, which you are encouraged to use along with pattern matching to make sure all cases are handled.Rust does not have exceptions. You never have to try/catch. Functions usually encode the possible failures in their types, so you’d have something like this C++ snippet:
And then the caller of
downloadFilehas to decide what to do if it returns an error:However, Rust makes this whole thing a lot easier, by providing syntax sugar, and there are helper libraries that reduce the boilerplate. You usually end up with something like
(notice the
#[from], which forwards the error message etc from thestd::io::Errortype)And the consumer code is something like this:
Or
Which will just forward the error to your caller (but your function has to return
Resultas well), or proceed with the execution if the function succeeded.Finally,
download_file(url).unwrap()is if you can neither ignore nor handle the error. It will abort if the function fails in any way, and there’s no (practical) way to catch that abort.It’s worse than that. In C++, if you fail to catch an exception, then std::terminate() is called. In Rust the only options are roughly equivalent to C++ noexcept, or std::terminate() [panic in Rust]. There’s nothing in between.
i’ve been meaning to get into rust; but i’m learning that i lack motivation if it’s not part of my job and becoming a sysadmin again doesn’t require it.
Thank you for the easier captchas, and pre-emptively damn you for whatever evil thing CloudFlare will eventually do with their MITM access to everything.
I shouldn’t worry about it.
.unwrap_or_ruin_christmas()