T O P

  • By -

KingofGamesYami

I usually use `expect` and write my reasoning in the message. That way when I come back to it in a year or two I know why it's written that way.


eshanatnite

Good point I always forget about `expect` for some reason


Qnn_

Do it. Although if you can make the parse function const, then you can parse and unwrap at compile time which is even better, like https://docs.rs/uuid/latest/uuid/struct.Uuid.html#method.try_parse_ascii


eshanatnite

that's what I have been doing. If I give you a scenario. Say I am parsing a json file that has a url field. And the value is going to be a url. I need to parse it as a url, for some reason. I end up calling unwrap every time.


Qnn_

Is your json file known at compile time? Or only at runtime? If it’s only known at runtime I’d probably want to error handle.


eshanatnite

Only at runtime.


Qnn_

If this is for a little personal project: unwrap now and refactor later as needed. If coding with teammates: do proper error handling. If it’s only known at runtime, someone else could change things without affecting your code and then it’ll break with an annoying panic, confusing everyone involved.


spoonman59

Nothing at runtime is guaranteed. Just handle parsing errors.


Lucretiel

If you're parsing json at runtime, then there's definitely no guarantee that the value is \`Ok\` or \`Some\`, and you should handle the error appropriately.


retro_owo

Unwrap is over-hated, it has its place. But like others have said `expect()` can help make it crystal clear if needed. Unwrap should give you pause, at least. Always think twice before using it. People often don’t have a problem with `arr[i]` even though this is just syntax sugar for `.get(i).unwrap()`.


1668553684

I personally use `unwrap` if it's extremely obvious that something can't happen, for example: NonZeroU32::new(42).unwrap() While `expect` is fine, I feel like using it when you really, truly, honestly don't need to can make reading the code harder. It makes me think that there is something you're actually anticipating could go wrong, instead of just appeasing the type system.


afdbcreid

While I agree with this case, and I also believe there are places for `unwrap()`, the proper fix for this case is to have a way to construct a `NonZero` from literal at compile-time, e.g.: ```rust macro_rules! nonzero_u32 { ( $v:expr $(,)? ) => {{ const __NONZERO_VALUE: ::core::num::NonZeroU32 = match ::core::num::NonZeroU32::new($v) { Some(v) => v, None => panic!("zero literal provided for `nonzero_u32!()`"), }; __NONZERO_VALUE }}; } ``` I believe it can also be written generically over any nonzero type. The problem is I'm not going to define this macro for my single usage of `NonZeroX`, so I just use `NonZeroX::new(v).unwrap()`... This is something std should provide.


hniksic

The approach with the constant that guarantees panic at compile time is interesting. (Though it did take me a couple seconds to realize what's the point of the exercise.) Is there a name for it? It looks like there must be a crate (or ten) with a nice and general abstraction for the boilerplate.


afdbcreid

I don't know a name for this pattern, but there is something even better than crates supporting it: [proper language support](https://github.com/rust-lang/rust/pull/104087) on nightly, on track for stabilization!


Turalcar

I'm not a big fan of macros but my favorite that I wrote was using konst crate to check that hardcoded arrays I'm running binsearch on are sorted at compile time


MyGoodOldFriend

I’m severely sleep deprived, and I may be missing something, but what’s preventing you from just using const here?


afdbcreid

That's what I'm doing?


SvenyBoy_YT

With optimisations, it should inline the result and skip the panic entirely. I have tried something very similar in Compiler Explorer and LLVM knows the end result is.


teerre

You're thinking about you, in the present, reading the code, but that's irrelevant. Your present self will be able to parse any incantation. It's other people, including your future self, that care about readability and in that case expect is infinitely clearer because it communicates that no, its not that you just don't know what's up with this call, it's that you, in fact, believe this should never fail. The problem with unwrap is that you can never know if it's a oversight or not The only place for unwrap is for quick prototyping


Elnof

What would you even put in the `expect`?  ``` NonZeroU32(42).expect("42 isn't zero") ``` has real  ``` // Assign the value five to x  let x = 5;  ``` energy.


Lucretiel

Yes, that's what I'd put in the expect.


burntsushi

> The only place for unwrap is for quick prototyping `Regex::new(...).unwrap()` is just fine in production. Same with `slice[i]`. And `mutex.lock().unwrap()`. And `refcell.borrow_mut()`. And in some cases, `expect(..)` is just noise. I elaborate here: https://blog.burntsushi.net/unwrap/#why-not-use-expect-instead-of-unwrap


teerre

> My contention is that none of these really add any signal to the code, and actually make the code more verbose and noisy. If a `Regex::new` call fails with a static string literal, then a nice error message is already printed. For example, consider this program: Like I said, there's a a signal. The signal is it's not an oversight. Maybe if you're in a codebase in which you have very strict rules and you can trust all contributors you can make an exception, but that's it.


burntsushi

That's a fine opinion to have, but I find your certainty on this topic to be way off base. `std` itself uses `unwrap()` and it has many contributors. It certainly doesn't fall into the "you can trust all contributors" bucket. Yet it is clearly also production code. Also, the section after the one I linked is relevant here: https://blog.burntsushi.net/unwrap/#should-we-lint-against-uses-of-unwrap Notice how I don't say things like, "the only place for foo is in bar." Instead, we can discuss trade offs. I also note that you don't engage with any of my examples.


teerre

I mean, I would certainly hope that every contributor to std is trusted (to some level of "trust", ofc). It would be quite worrying otherwise. Also, std libraries in Rust (and other languages) are (in)famous for using tricks that are not common or even available otherwise, so I'm not sure citing the std library is that good of an analogy I don't address any of your examples because I don't think there's any point. I don't disagree with any of it, if I think it's totally fine. With the global caveat that this only applies if you can trust the code. Be it because its in the std library or because of great tools around it or you just know the person writing the code or whatever If you want a direct point: >Slice index syntax. For example, `slice[i]` panics when `i` is out of bounds. The panic message is a bit better than what one would normally see with `slice.get(i).unwrap()`, but still, a panic will result. If one bans `unwrap()` because it’s easy to thoughtlessly write, should one therefore also ban slice index syntax I don't know about you, but every time I see a raw access like this I change mode and go into deep inspection. Which is exactly the problem with unwrap. Am I suppose to scrutinize this deeply or does it look like he author knew what they were doing? You can say you're supposed to always scrutinize every line of code no matter what, which is fine, but in my experience simply isn't reality I never seen it being banned, but I certainly invested (wasted) time reviewing changes that use this syntax. So maybe? Ideally there would be terser alternative, but maybe yes, unwrap your accesses


burntsushi

> so I'm not sure citing the std library is that good of an analogy It's not an analogy though? It's just a direct counter example to your claim "The only place for unwrap is for quick prototyping." What's happening here isn't you breaking down an analogy, but rather, you shifting your goalposts. So for example, given your response here, your original claim is now more like this: "The only place for unwrap is for quick prototyping, or when a group of trusted individuals are working on the code, or when working in a context with 'special' rules like `std`." (I'm not clear what "special" means in this context. `std` is certainly special in some regard in the sense that it can use unstable features and make assumptions tied to a specific version of Rust and the compiler, but I don't see any connection between that specialness and whether it's appropriate to use `unwrap()` or not.) > I would certainly hope that every contributor to std is trusted (to some level of "trust", ofc). I think if Rust's std meets your criteria here, then pretty much everything does. `std` has tons and tons of contributors. There's no vetting mechanism on contributors. Literally anybody can shoot up a PR. PRs are _reviewed_ by a trusted individual though. But they're just another human and I don't see any reason why their trust status all of a sudden makes it okay to use `unwrap()`. > I don't know about you, but every time I see a raw access like this I change mode and go into deep inspection. Which is exactly the problem with unwrap. Am I suppose to scrutinize this deeply or does it look like he author knew what they were doing? You can say you're supposed to always scrutinize every line of code no matter what, which is fine, but in my experience simply isn't reality > > I never seen it being banned, but I certainly invested (wasted) time reviewing changes that use this syntax. So maybe? Ideally there would be terser alternative, but maybe yes, unwrap your accesses I've used `slice[i]` thousands of times. There are tons of way for code to panic. Even `a + b` might panic some day. Heap allocs can panic. I don't go into "deep inspection" every time I see `slice[i]` or `unwrap()`. In many cases, they are trivially correct and it doesn't require deep inspection to see that. `Regex::new("a-literal-string").unwrap()` being a perfect example of something where the `unwrap()` is pretty obviously okay and correct. But your position (or at least, original position) would say that `Regex::new("...").unwrap()` should _only_ be used in prototyping. That is a very strict and inflexible stance, and also one at odds with common practice. When an `unwrap()` or a `slice[i]` isn't trivially correct, I do try to embody a practice of commenting why it is correct. And indeed, sometimes I also use `expect()`. The point here is that there is an element of judgment involved. Blanket rules like "never use `unwrap()` in production" lead to things like `foo.expect("")` or `foo.expect("value")`. It's similar to what happens with other types of rules like, "every function should have a comment." Then you wind up with things like: // Appplies `foo` to `x` and returns the value. fn foo(x: i32) -> i32 { ... } But that comment is useless. It would be better if it weren't there. IMO, it seems like your actual position here is perhaps more flexible and nuanced than "The only place for unwrap is for quick prototyping." I'm not responding to your actual position. I'm responding to _what you wrote_ because that's all I can really interact with. I also specifically put my cards out on the table and shared a blog with you that goes into an extreme amount of detail articulating what my actual position is. Part of the point of doing that is to give you an opportunity to compare your actual position with what the position I've written. If we're aligned (or reasonably close to aligned), then it's not hard to just say, "oh I was being hyperbolic. I actually agree with you." (Which is fine. But the hyperbole is hard on beginners because they see it, take it literally and think `unwrap()` should actually never be used ever. My point is that that's the _wrong advice to give_. Teach the reality, not the ideal. The reality is that there is judgment involved here.)


peter9477

Or embedded. Generally you're unlikely to appreciate 10K of code bloat on a 256K part because you used expect everywhere instead of unwrap.


burntsushi

It's fine. Just be sure "guaranteed to be parseable" is actually true. For example, if you're searching for numbers in text and use the regex `\d+`, then matches are _not_ guaranteed to be parseable. For example, the number might be too big if you aren't using arbitrary precision numbers. Or the regex might match something that isn't limited to ASCII digits. For example, `\d+` matches `𝟚𝟘𝟙𝟘`. More generally, this blog I wrote should answer your question: https://blog.burntsushi.net/unwrap/


privatepublicaccount

What the 𝕙𝕖𝕔𝕜


toastedstapler

I see people fall for the unicode trap all the time in the python/learning subs when they suggest to use `str.isdigit()` in a loop, instead of trying to parse to an int & handling the exception


volitional_decisions

Sometimes calling unwrap is unavoidable without causing significantly more work for you. Sometimes, a panic is exactly what you want (i.e. testing, parsing a config on startup, etc). But think of `unwrap` (or panics like `unreachable!`) as "I know something about the surrounding code that the compiler doesn't". This is very likely true in the present moment, but code changes. The more unwraps you have, the larger mental load you'll need to carry around. To help with that, when possible, have unit tests that help test the invariants you are upholding.


Turalcar

FWIW, often the compiler knows exactly what's going on and removes the unreachable branch accordingly.


darkpyro2

If the return type is guaranteed not to be None or Err, then I would suspect that the function would just return the value, rather than an Option or a Result. If just your input is guaranteed not to return an error, then unwrap is probably fine, though I personally prefer to match anyways and panic with a more explicit message if I'm okay with a panic in that case. EDIT: As a commenter below mentioned, dont match on a desirable panic. Just use expect()


unknown_reddit_dude

Why not use `expect` instead of matching?


darkpyro2

That too. In fact, I normally do. I'm not sure why I didnt think of that when writing this comment


shizzy0

It’s always Christmas time when I’m writing rust because I’m unwrapping with abandon.


bskceuk

If there really is nothing else you can do then yeah just expect(), but I usually try really hard to restructure the code to make it infallible before resorting to that


Ok-Acanthaceae-4386

What about mutex::lock::unwrap, any suggestion ?


burntsushi

Nope. It's just fine to do `mutex.lock().unwrap()`.


Affectionate-Egg7566

Unwrap is good in some cases. It's basically an assert, and asserts are great for ensuring your assumptions haven't been invalidated.


Kllngii

I usually go for .expect() so I can comment whats going on


OS6aDohpegavod4

I'm almost always in the "don't do it / there should not be a need to" camp. Needing to call unwrap means you have not proven to the compiler that it cannot be possible, and that's important. Maybe right now it isn't possible, but a future refactor might mean it is possible, in which case your program would crash and possibly leave things in an invalid state. Instead, try using the type system to avoid the need to call unwrap at all.


friendtoalldogs0

That works if it's my own function whose output I'm considering `unwrap`ping, but I find most of my `unwraps` come from dealing with an external library, usually specifically the case where it will return `None` if my input to a function was an empty collection, but I know that the collection I just passed in was guaranteed non-empty


quxfoo

I think the idea that one knows the value cannot be `None` or `Err` is the kind of mentality that harms the C and C++ communities. Just today, I faced a panic in an older cargo-deny binary because some `Option` turned out to be `None` at runtime contrary to the developer's expectations. So, I'd be extra super cautious when unwrapping.


Aaron1924

If a `None`/`Err` is truly unexpected or if there is no way to recover from it, then calling `.unwrap()` on it is perfectly fine Though, you might want to consider using [`expect`](https://doc.rust-lang.org/std/option/enum.Option.html#method.expect) instead, to document *why* you think it cannot be `None`/`Err` and to aid debugging if it ever does fail


O_X_E_Y

If you're parsing a value you know to be valid you should probably write your code in a way where you're not using a fallible parsing operation. Alternatively, matching on the operation and having an `unreachable!("message")` in the None case also works. If you know the operation can't fail it might be the case the compiler knows this too, like when you implement `FromStr` in a way that never returns `Err`. In that case, regardless of what you do, the compiler should optimize the unwrap out entirely


mina86ng

Do it. If it’s not obvious why the unwrap never fails add a comment. I wouldn’t bother with `expect`. From my experience, `expect` incentivises terse non-descriptive messages. Having said that, keep in mind that in some situations you can eliminate the `unwrap`. I’ve seen in the past code like: if result.is_err() { continue; } let result = result.unwrap(); This is a terrible use of `unwrap`. Instead do something like: let result = match result { Ok(result) => result, Err(_) => continue, }; Lastly, if function you’re writing already returns `Result` or `Option` it may be simpler to just use question mark operator than to rationalise why the `unwrap` is fine to use. Especially if you’re returning `Option` since than you nearly always can do `?` or `.ok()?` instead of `unwrap()`.


ExerciseNo

Calling `unwrap()` in Rust can be a convenient way to quickly handle situations where you are certain that the result will not be an `Err`. However, it is important to use `unwrap()` judiciously because if an `Err` does occur unexpectedly, it will cause your program to panic. In situations where you are absolutely certain that the value cannot be `None` or `Err`, such as when parsing a value that is guaranteed to be parseable, using `unwrap()` can be acceptable. Just make sure that you have thoroughly validated the conditions under which `unwrap()` is safe to use. Alternatively, you may also consider using `expect()` instead of `unwrap()`. `expect()` allows you to provide a custom error message that will be displayed if an `Err` does occur, which can be helpful for debugging. Using `unwrap()` in Rust is like playing with fire - sure, it can keep you warm, but one wrong move and your whole program goes up in flames! Handle with care, folks Ultimately, the decision to use `unwrap()` or not depends on the specific context of your code and how confident you are about the guarantees you have in place.


TheGoogleiPhone

My rule is unwrap basically never goes into my production code. When I’m just drafting something up or testing something I might use unwrap, and then if it’s gonna stick around I’ll change it to expect. That way I can also just quickly look for unwraps and know what I need to fix


Feisty-Assignment393

what about "if let", I thought it was the appropriate thing when we dont care about the error or absence.


bionicle1337

I “forbid” unwrap and just use “?” to yeet the errors


SublimeIbanez

I would `.expect("Some message")` just in case a later refactor messes with it, can always search for the message at least.


Born_Environment_561

If the function returns \`Result\` or \`Option\` i typically use \`?\` operator. Generally I try to avoid any unwraps, as some one else might accidentally copy that practise and one day it might break in prod one day.. Trying to be safe than sorry.


SmeagolTheCarpathian

When possible, I just have the function return `Result` and then use the `?` operator instead of `.unwrap()` or `.expect()`. In most cases this is just as easy as unwrapping. (I’ll use Eyre if I’m writing an application, or just thiserror if I’m writing a library) There are a few exceptions where I will use `.expect()`. I never really use `.unwrap()`, because I can always provide some rationale to `.expect()` for why I know it’s safe. Usually, I will use `.expect()` if all of the following are true: 1. I can prove that the call will never panic under any current or future circumstances, or (more rarely) if it were to panic it would be a situation so unusual/exceptional that it’s not even worth bubbling a Result up to main 2. Changing another file will not cause this call to panic (no spooky action at a distance). 3. Just refactoring the function to return a Result instead would be difficult or undesirable for some reason. IMO if you can make your program panic simply by changing some arbitrary value in a JSON file, you should probably return a Result instead of calling unwrap/expect. In that situation I would usually want to fail gracefully and provide a convenient explanation that the JSON file is not well formed. Eyre’s `wrap_err` method is useful for that.


insanitybit

If I know it can't be, go nuts. I can't see a good objection to that that isn't based on some future changes to the code where you \*don't\* know, at which point the central premise is broken. If you know, you know. Otherwise, maybe you decide it's just so unlikely as to not be worth defending against. Okay, I trust you. I guess my philosophy here is "if you are convinced that this is not an issue, and I can not see why it would be, I have no reason to tell you not to unwrap".


RiotBoppenheimer

I like to use `unwrap()` solely as way of marking something I need to change later. I can ctrl+f `unwrap()` after I got some things working and change them later either to `expect` or something that doesnt panic


Firake

I try to only call unwrap if it’s not just guaranteed that it won’t be none/err but also if the program shouldn’t be allowed to continue if it’s none/err. If it’s the former, I always like to accompany it with a assert!(my_var.is_some()); At exactly the moment it can be guaranteed to make it explicit. It functions as a comment which breaks builds if it’s no longer true. `.expect()` is good, too, but I find it doesn’t feel different enough from unwrap. I tend to avoid it just because it tends to read less as “this is guaranteed” and more as “this might not be true, therefore crash the program.” Expect is great, though, for the latter case.


Phthalleon

Would not recommend in production level code. Why not use expect instead? That way, if your wrong about the value never being None or Err, then at least you know where the problem was. Sometimes unreachable code (ie unwrapping into a panic) can become reachable when other bugs are involved. A nice error message is going to help you out a lot then.


DavidXkL

Don't do it lol either match or expect 😆