Change:
Feature gate: This is a tracking issue for and . [x] Implementation: [x] Final comment period (FCP) trait in ? <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
I propose to discuss adding , , , methods as described in before stabilizing
I kind of like the idea of . It could be very useful in long method call chains to, for example, spit out a warning. On the other hand, I don't think it's necessary to rename into and into . Considering is not named and and is not named and , I think using the simple name maintains more consistency.
what are the next steps to stabilize this proposal?
Could this somehow enable the following? I suppose the current alternative is: But that is not really pretty, especially when assigning to fields or directly in a function call:
You can already do this with map, with something like (or to get access to the value later), inspect wouldn't work I think since it gives you an immutable reference to the item. Alternatively we could add inspect_mut or something, but it doesn't feel like there's a whole lot of usecases for it.
You might be looking for something like  instead of . As the name suggests, ing an object doesn't change it. Whether accepts this convenient method is entirely another topic, which falls into the question of whether we want to include ping or not.
Any progress on an FCP?
Another set of hands for stabilizing this feature. I think it is very useful for e.g. logging a given error too and it's a nice addition in general
Ok, from what I understand of , we should first make sure there are no outstanding concerns. The correct thing to do should be to ping one of the libs team members like to give their comments and then potentially file an FCP.
I don't know how much help I can be to the process, if at all (please let me know if there are things to read about how I can help at all^), but I would like to mention that I have found myself wanting to use this functionality quite often. It makes for clean code in a pretty common situation. ^I'm relatively new to Rust, and haven't contributed to it before. I would love to learn more about what that involves, though.
I think this would be a nice addition, not sure how to push it forward though.
Most of the time when I want for (or ), I want the closure to be passed the entire thing (i.e. ), rather than just the or (or or ) value. That is, I want to write: rather than: If we wanted, we could still add , , , and for the cases where they might be more convenient. But we would not need to, as this version of would have the power of all of them. Arguably, this definition is more consistent with , as that method sees every item. I would find it a bit surprising if didn't see everything that's passing through the method chain. For concreteness, here is the API I propose:
That makes sense to me. I would definitely say that adding , , , for convenience would be a good idea to go with this proposal - I think there are many times when you want to inspect the 'whole' or , but also many times when you wouldn't.
There’s nothing special about an inspect that has the whole value that should be limited to — any type whatsoever could apply. That’s the tap crate
That's true. Fair enough. Thanks for that. Above, the body of this ticket has an unresolved question: This discussion suggests that, yes, there probably should be.
Instead of a trait, could be a which would allow for things like: Where logically takes an , takes a , and the versions only run if the value matches the pattern.
I definitely second emulating the tap crate's behavior, favoring approach. Having a variant could be super convenient, especially with both mutable () and immutable () variants.
I don't necessarily like the addition of a macro for this, tbh, and would love to see this going the trait in std way. Also, with postfix macros it would depend on another RFC (). That being said, anything needed for bringing this forward?
i just ran into this because i found the feature and it'd be quite useful for me. as pointed out by others, being able to call that would clean up a lot of logging code, even in otherwise non-fluent code. e.g. for this use-case here: or, even simpler, when you don't actually need the result afterwards: and i think that this is distinct from the use-case where you want access to the complete object. so i think the two can be looked at separately: the APIs introduced by this feature here a -like API in (or, hopefully, for support?) as a separate feature
I completely agree, API seems like a different feature. and are common in code bases i work on because they exist on (). Searching on GitHub also shows quite a bit of hand-rolled implementations. I think this is a pretty good indicator of the usefulness of API.
What's blocking this from being stabilised?
I would also like to see this stable, so I can deprecate my and crates! :laughing:
As many have mentioned, this would be a very useful feature. I have some errors that are soft failures with a fallback, but I still want to log them. Here's how I currently do it: And here's how simple it would be to do with : The difference is small, but I feel like syntactically it is wrong to say that I am "mapping the error". We should leave to work on rather than the entire to match the behavior of , , ... Those all have an equivalent function that works on . I'd say should work on and on .
Sorry to chime in late, but I just saw the suggestion to have closure take the whole object. I have to say, I'm having trouble making sense of the idea. Wouldn't you just take the object as-is, then? Especially since is a const function that just prints or "inspects" the item without mapping or changing. For example, the code listed above: would seem more straightforward, rustic, transparent, and simple as: would it not? Do we need to add a whole implementation just to inspect the object itself when we have the object? Just to make it perhaps appear more "functional" (although I'm not sure I'd call it more functional in truth since it adds or subtracts nothing from functional principles)? I'd vote to keep as the "Ok/Some" version and for Err() (I don't really think an is adding anything to the class, to be honest). Anyways, just my two cents...
What still needs to be done for this to be stabilized?
If a more general trait will be , and the method will be named as , should we reserve the name for it from ? This is a point of view that supports . Although I personally like a bit more, since it has a consistent naming style with the existing , , etc.
Any progress on this feature?
Yeah, this would be really nice
I asked about it on this but got no answers. Maybe we should ping someone from libs team to help us set a direction for this feature.
Since we already have  for an iterator, it is consistent to keep as the version.
Any news? It's extremely common to log an error before using the try operator, something like: Instead of the verbose current equivalent:
that can be shorten a bit, but your point is valid nonetheless: rust let foo = falliblecall().maperr( { log::error!("{e}"); e })?;
For those who are following this closely, there's been some discussion in a recent Libs-API Meeting: I'd like to share my experience with this issue. I discovered while I was trying to perform some side effects in the middle of a chain. I needed to inspect the intermediary result to perform some computation. I use stable Rust on VS Code + Rust-Analyzer, and I got some completions from Rust-Analyzer for , which did exactly what I needed: It gives me a way to perform a side effect without changing the processing chain. I was a bit sad to see it be unstable, as I 'stumbled' on it out of need. Also, I think idioms would be easier to read. When I read , I don't usually expect side effects happening. I usually expect a type being transformed into another. It's a little surprising to see a being used but not performing a mapping at all: If this issue ends up not being accepted, then we could have some "go-to" crate to provide this extension and see if more people see the need for this idiom over time. With this issue open without definition, people (including myself) may wait for a decision before going to a third-party solution.
For this specific purpose, I found very useful, more specifically, 's and .
We discussed this in a recent libs-api meeting, but most of us had trouble forming strong opinions (in favor or against). An FCP would probably not get enough support at this point. In general, we tend to be quite careful with adding more methods to types like Option and Result, since they form part of the 'vocabulary' one needs to know to write and read Rust code. There is value in keeping that vocabulary small, of course, but it's always a trade-off. Personally, I wonder if is worth it as an additional way to something similar to what (or ) already does. I think it could perhaps be cool if basically everything in Rust could be written as part of a chain, e.g. postfix macro, or postfix , etc, but without such (language) features, I'm not sure if significantly changes how much can be written as a chain, but I'm happy to be convinced otherwise. Tangentally, I think it's a shame that a simple type such as Option has so many methods. It means that if I make my own I need to consider adding all those methods to make it as ergonomic as Option or Result, adding a higher bar for using custom types. Ideally, there would be some kind of language feature that would cover all common enum functionality like , , , and so on with some short and easy syntax, but I can't think of anything that would work well. I am afraid that and especially will often lead to patterns where you'd want the inside the closure to apply to the surrounding function, which it doesn't. A language feature that would not be based on closures wouldn't have this problem. (Just like , although that feature is more (too?) verbose of course.) Anyway, I'm a bit on the edge on whether we should stabilize this or not, but I could be convinced with some more (real world!) examples, such as places where similar methods from community crates are already used, or places where could make code easier to read. I think the same holds for other members of the team. :)
A problem that has come up a few times for me that I think is closely related is logging an error and returning with a default return value that is no – common values being , and . Currently I would say the most convenient way of handling these is , but that throws away the error message: If the default return value is like in the example above, a good alternative that does include the error message in the logs would be However, as it's only a partial solution (doesn't work for other default return values) I agree that it doesn't feel great. I also agree that postfix macros might be the answer here. Specifically, would allow: which seems much better than my current go-to of (an where the success branch just evals to a binding from the pattern is practically equivalent in terms of redundancy / noise)
We're using to log stuff in quite a few places in mirrord. It feels more right than , and it's more convenient than , as we're chaining stuff. Couple of examples:
I can understand if it's not the most compelling use-case, but like logging stuff is definitely the main reason I want this.
In both of those examples, would have worked just fine, right? In both cases, the error value is not used afterwards. I'm not saying that I think is the perfect method for those use cases, but I find it interesting to see that while is designed to leave the error value in tact, that value is immediately thrown away afterwards.
nah, I wouldn't use for this at the end of a method chain, I'd just if it's being put in a variable or wrap the whole thing in a if it's a return position expression or something I think the discussion on this issue has ended up asking for something different than what I actually wanted when I decided to subscribe to the discussion. I wouldn't want an method that gets and an method that gets . I wanted an method that would get . Here's really what I had in mind: I can in here and get the full picture I could potentially do something side-effecting based on an intermediate value without "mapping" a value and needing to return the correct thing if I want a (potentially different) side effect regardless of whether the value is or , I can do that in one place to make it clear that they are linked this is a slightly half hearted defence, because obviously we've all been getting along just fine without any of this. it's probably better to just split the method chain by storing the first half in a variable and making a non-owning copy with , do your side effects, and then resume the method chain on the owned value. and an intermediate could just look like... Also this kind of diverges from what usually means (for an iterator) and what means for a result. Yeah ok, this has turned into a very long winded "I don't actually want this anymore"
Adding my example of code where I wanted to use (it's a bit cursed to I'm not sure it's a good example but still ):
But speaking of more powerful alternatives, I quite like the idea of an extension that allows to inspect any value: With that you can easily simulate (): But you could also chain anything, really. It's really nice for chaining methods for example (): Upd: did not notice that the OP mentioned , which is basically the same thing. Oops
Wow, I managed to pick up 2 examples where we throw out the error, but that's not always the case, my bad. , and should give a feel for how often we reach for it. btw: I'm not strongly in favor of the feature, as I agree with your notion of "too much stuff in Result/Option" (especially since we implemented our own Result-ish thing). IMO, this is a nice to have mostly for looks (as it's implemented, not talking about the discussion), where looks a bit less fancy.
On argument regarding the vocabulary that one need to learn to write rust code. I found it myself counter intuitive that iterator chains support .inspect but result and option not. For me it would feel more consistent to find the same or similar idioms all around the std lib. Which is of course often the case, here in particular not.
Sadly, I can’t put a link to the actual code because the repository is not public, but we are also using it at work for simple data inspection and logging. Here is a simplified excerpt that I’m allowed to share (using the crate): Without , I would write the following: I don’t feel the latter is particularly more readable than the former. Note that: This is somewhat repetitive, boring code and a shorter way to write it was much welcomed. We didn’t add to all our crates and I often end up writing code without "taping", because I wanted to stay focused on my task without breaking the flow. That’s because , while being a nice quality of life tool, is not absolutely essential to tackle the task. Note also that instead of short-lived bindings all named , I gave full explicit names in the latter because I don’t want the reader to confuse the binding for the handshake result with the binding for the start active stage request. Indeed, it’s arguably easier to make a typo and log the wrong value: If not for that, I don’t feel like there was a need to have a long explicit name for the bindings given that the value itself is short-lived. An alternative would be to introduce shorter scopes: I don’t worry about all that when "tapping" because, precisely, the bindings are clearly short-lived and no shadowing is happening. EDIT: The above was assuming some kind of -like API which is not exactly covering. Only half of the "problem" is addressed by : As mentioned by others, the next logical step would be a trait, but I believe this still demonstrates how "similar methods" are actually used in practice
One more thing regarding The std lib has a lot of places where is used. That however is also not standardized via a common trait. Hence I wonder if a generalized trait like really must be coupled to the stabilization of this very feature. IMHO a trait for a common seen behavior could also be introduced late. Later than the here discussed feature is implemented.
Indeed, my understanding is that a separate RFC is required for that. The trait is not even generalizing the / methods. The "tapping" methods are simply giving a view to the value as-is while / is performing pattern matching, so that’s really different.
We discussed this in the libs-api meeting today, and the consensus was that we're mostly happy to add this. However we would like to change the signature to give a to the closure instead of a . fcp merge
Team member has proposed to merge this. The next step is review by the rest of the tagged team members: [x] [ ] [x] [ ] [ ] No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See for info about what commands tagged team members can give me.
No strong opinions either way, but to clarify, taking an is an intentional inconsistency with whose closure takes an ?
Am I missing something here? Why would we have a mutable reference? Isn't that what is for, essentially?
Is there a transcript of this meeting or the minutes? I am interested in why inspect is able to potentially mutate things? In code reviews I’d have to be careful if I see inspect, as my first instinct is that it is a “safe” function to call whenever. If it is now mutable, and closure args don’t have their types spelled out, it is easy to miss.
I am of the strong opinion that the name heavily implies immutability. Add to this the consistency issue with , I am staunchly against allowing it a . I mean, if it gets a it really should be named . Not a great name for sure (but again, we do have  so what do I know) but it's better than this.
The rationale for allowing to mutate the value is that it's a generally useful operation, and it avoids the need to add a separate method which gives mutable access to the contained value. We want to avoid the situation that happened with where we initially only gave immutable access to the closure, and required adding a separate method which does the exact same thing but with a mutable argument to the closure. We felt that the name was still appropriate for this. Rust syntax generally makes it very explicit when mutation is happening, so we don't expect this to be a significant problem with code reviews.
I disagree here, for a closure, getting a or a uses the same syntax as the mutability is in the type. I feel like that's a good idea to prevent. But since its different from why not rename it? Some other names that would fit the new signature better: - - Unrelated to the name, I consider this somewhat of a bait-and-switch? From the beginning this thread was discussed as taking an immutable parameter... Especially since allows to do the exact same thing that this new "" would do. (After all, you are not obligated to change the underlying type.) As a personal opinion, and less in the wider POV of a community, I was waiting for since in the moments where it is useful, it is missing. But having it be able to mutate, makes it break the 'unsurprising' part and means that I can't really consider using it.
I'm just a random user, not sure how much weight anything i say holds here. The dictionary definition of inspect goes as follows: couple this with the fact iterator inspect is immutable, I'm quite sure a mutable inspect will cause a lot of confusion. i also don't understand in which cases .map()/.map_err() couldn't be used instead of a mutable inspect. a lot of things would be very useful, it doesn't feel like a great argument for this change.
I would argue that an is by name already only a read only operation. So is not the right choice IMO. For the need to mutate the value exists already plenty of features, mostly would be the default choice. IMO to keep this API as close and consistent as possible to the I would rather see this as a .
I'm going to cancel the FCP since this turned out to be more controversial than I expected. Given the reactions, I'm not entirely opposed to changing this back to . fcp cancel
proposal cancelled.
Thank you for being so receptive to the community, in particular how quickly!
The [] crate named the adaptor with access to each yielded value []. While is not equivalent to , I believe the name fits, if the mutable version is still up to debate. <subSorry to the people who see this in their inbox twice, once partly, I accidentally hit <kbdShift</kbd+ <kbdEnter</kbdin a draft state.</sub[]: []:
I’m glad to see the vocabulary of inspect won’t become ambiguous wrt const or mutable access. Matching iterator would be appreciated.
If you want to mutate something in the passed value, I think is good enough, as its use implies that something is being changed. In fact, I've made a comment before about how working around the lack of with was weird because with you expect something to be different. So, IMO we're good with on .
Just as a counter voice, I would be fine if 's closure argument was of type . To me, is all about performing side effects. Those side effects could include: printing/logging modifying a captured variable modifying the closure's argument Printing and logging modify global state, and people are generally OK with that inside of . Indeed, that seems to be a huge usecase. The closure is as opposed to , which allows us to modify (or even consume!) the variables captured by the closure. I haven't seen any complaints about that choice, even though it's been there for 75+ weeks. Even in a case where 's closure takes , that might still use interior mutability. That is, there's no guarantee that doesn't modify data inside of .
is a whole other beast, IMHO. I personally wouldn't expect an to change things without my consent in real life, e.g. on a car inspection. I would rather ask for what needs to be changed to explicitly change it, then in the next step. Furthermore, I think this is kind of the social contract that as a word implies. Changing that, would be weird and contrary to the .
is already used by iterators. does not provide mutability, so shouldn't either. There should be consistency in how things are named. I see zero reason to not just stabilize this feature now with the signature of .
How do we push this to get stabilized?
on should take , which is the most consistent to . IMHO, one of the most important things when designing something is: how well it interacts with other features how consistent it is to other features how intuitive it is to learn/understand Something is intuitive to learn, if you only need to learn a concept once and can transfer that knowledge to other parts of the system that should behave the same (according to what has been your "entry point" of learning the concept). When we take those three points, we might come to the following conclusion: resembles the shape of an (like , , ) - they can also easily be turned into an (they implement after all). =When methods on and with the same name exist, they should be as similar as possible. In  the generic closure has the type : , because when we iterate over more than one element, we need to call the closure more than once (this is not necessary for as they only contain at most one element) , because we don't want to change the value we are ing on should take , which is the most consistent to .
Considering the points raised, let's try this again, this time keeping the closure argument as . The fact that this function is not as general as it could be isn't a big issue: after all this is just a convenience method, you can always use for the more complex but rarer cases where mutation is needed. fcp merge
Team member has proposed to merge this. The next step is review by the rest of the tagged team members: [x] [x] [x] [ ] [ ] No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See for info about what commands tagged team members can give me.
:bell: This is now entering its final comment period, as per the . :bell:
I would like to work on a stabilization PR for it. claim
Since has almost been accepted, perhaps we should reopen PR for adding ? Some discussions about it:
I would like to chime in on naming - I originally wanted to come argumenting for / but since writing it down it is less clear now. Anyway, here are my arguments either way 1) it makes it explicit what I am inspecting. Explicit is always good in my opinion (downside is slightly longer code) 2) it makes it way easier to distinguish "inspect" calls on different types - this might be good or bad depending on whether one wants more clarity ( vs ) vs ease of refactoring (e.g. when changing to or vice versa). On the other hand, we already have a precedent with working on both types 3) most notably, I would like to have some general / call on every type in the future. Right now Rust is clunky because while many times you can use functional approach you also frequently need to drop down to more imperative style just to e.g. log something. In an ideal case, I would like to see something like as opposed to The second version is harder to read because on the first glance it does not "tie" computation with logging and you need to go through the whole line looking for "x" to correlate it. Similarly, using for chaining operations would be very helpful (although tricky to add at this point). While this RFC does not address either general nor general , I suspect reserving instead of would make any such future efforts harder to push because we would need to either find a new name for such a method or live with a fact that general inspect on Option/Result would be clunky and sometimes inspecting whole value actually makes sense - consider quick debugging like - in this case I want to see both and paths.
The final comment period, with a disposition to merge, as per the , is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. This will be merged soon.

Discussion:
#![feature(if_let_guard)] #![feature(let_chains)] #![feature(never_type)] <del> #![feature(result_option_inspect)] </del> #![feature(rustc_attrs)] #![feature(yeet_expr)] #![feature(try_blocks)]

#![feature(extract_if)] #![feature(intra_doc_pointers)] #![feature(yeet_expr)] <del> #![feature(result_option_inspect)] </del> #![feature(const_option)] #![feature(trait_alias)] #![feature(ptr_alignment_type)]

#![feature(let_chains)] #![feature(if_let_guard)] #![feature(never_type)] <del> #![feature(result_option_inspect)] </del> #![feature(type_alias_impl_trait)] #![feature(min_specialization)] #![recursion_limit = "512"] // For rustdoc

/// # Examples /// /// ``` <del> /// #![feature(result_option_inspect)] /// </del> /// let v = vec![1, 2, 3, 4, 5]; /// /// // prints "got: 4"

/// let x: Option<&usize> = v.get(5).inspect(|x| println!("got: {x}")); /// ``` #[inline] <del> #[unstable(feature = "result_option_inspect", issue = "91345")] pub fn inspect<F>(self, f: F) -> Self where F: FnOnce(&T), { </del> <ins> #[stable(feature = "result_option_inspect", since = "CURRENT_RUSTC_VERSION")] pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self { </ins> if let Some(ref x) = self { f(x); }

/// # Examples /// /// ``` <del> /// #![feature(result_option_inspect)] /// </del> /// let x: u8 = "4" ///     .parse::<u8>() ///     .inspect(|x| println!("original: {x}"))

///     .expect("failed to parse number"); /// ``` #[inline] <del> #[unstable(feature = "result_option_inspect", issue = "91345")] </del> <ins> #[stable(feature = "result_option_inspect", since = "CURRENT_RUSTC_VERSION")] </ins> pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self { if let Ok(ref t) = self { f(t);

/// # Examples /// /// ``` <del> /// #![feature(result_option_inspect)] /// </del> /// use std::{fs, io}; /// /// fn read() -> io::Result<String> {

/// } /// ``` #[inline] <del> #[unstable(feature = "result_option_inspect", issue = "91345")] </del> <ins> #[stable(feature = "result_option_inspect", since = "CURRENT_RUSTC_VERSION")] </ins> pub fn inspect_err<F: FnOnce(&E)>(self, f: F) -> Self { if let Err(ref e) = self { f(e);