Rust: Tracking issue for Option::xor

Created on 7 May 2018  路  25Comments  路  Source: rust-lang/rust

Today I got myself in a situation in which I had two Option<T> values, and I wanted to return the only one that was Some. If both of them were Some, then I'd rather return None. I think it would be perfect to have a xor method, very similar to the or method:

impl<T> Option<T> {

    //...

    fn xor(self, optb: Option<T>) -> Option<T> {
        match (&self, &optb) {
            (&Some(_), &None) => self,
            (&None, &Some(_)) => optb,
            _ => None,
        }
    }
}

I think that would solve my problem nicely, and could be useful for a lot of people as well.

B-unstable C-tracking-issue E-easy T-libs disposition-merge finished-final-comment-period

Most helpful comment

There would be no point in a xor_else because you always have to evaluate the second argument.

All 25 comments

There should also be an xor_else method, similar to or_else.

There would be no point in a xor_else because you always have to evaluate the second argument.

鈥ood point. Never mind, then.

Implemented on #50553.

@Milack27 You actually need to keep this issue open as a tracking issue. It hasn't been stabilised yet, so, it can only be used with #![feature(option_xor)] at the moment.

If you could rename this issue to "Tracking issue for Option::xor" it would also help make that clear.

@clarcharr Oops, sorry! Just fixed it.

Aren't new methods supposed to be added via RFC?

@pravic I don't know. The same concern was raised in #50553, but it seems the approval of the libs team is sufficient. Initially, I just posted this issue as a feature suggestion, expecting to get the opinions of the community members before going through the RFC process. Nevertheless, I can still write an RFC if it's needed.

@pravic depends on what kind of method. Simple ones like this are implemented and left unstable to be used by the community, and usually that + a final comment period is enough to accept a feature. Ones that are more iffy on the design need RFCs though.

@sfackler Quite a bit of time has passed since it was first implemented on the 18th of May; How do you feel about stabilizing this?

Seconding @Centril's question, it's now February 2019

@rfcbot fcp merge

Team member @sfackler has proposed to merge this. The next step is review by the rest of the tagged team members:

  • [ ] @Kimundi
  • [x] @SimonSapin
  • [x] @alexcrichton
  • [x] @dtolnay
  • [x] @sfackler
  • [ ] @withoutboats

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 this document for info about what commands tagged team members can give me.

Seems really niche, I'm not sure if adding another method to option is worth the externalities of that versus people writing match statements

Fwiw, I think opta.xor(optb) is useful in situations where you e.g. have some optional configuration a, and optional b, and then you only want one of them or it is an error otherwise.

Just for the sake of curiosity, Option::xor would have been useful to me when I was solving the Advent of Code 2017. I needed to parse a text file like this:

     |          
     |  +--+    
     A  |  C    
 F---|----E|--+ 
     |  |  |  D 
     +B-+  +--+ 

Then, I had to follow the path and collect the letters. I could have used Option::xor to decide where to go next when I met a corner. Here's a simplified version of the code:

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=cda2bdf9c41964c8aeb01916bd817c2d

:bell: This is now entering its final comment period, as per the review above. :bell:

Note that the same thing can also be expressed as opta.is_some() != optb.is_some(). Do we really need a separate method just for this?

@Amanieu opta.is_some() != optb.is_some() returns a boolean, while opta.xor(optb) returns an Option.

Does this method exist in other languages? I've never seen such a method in OCaml or Haskell, both languages which make extensive use of option types and have been around much longer than Rust has. That should make us doubt whether this is useful enough to belong in the standard library.

@lfairy Your point is reasonable. I'm not familiar with either OCaml or Haskell, but I'd like to point out some possible arguments in favor of Option::xor that could be taken into account when comparing Rust to those languages:

  1. Rust already has a stable Option::or method, which works pretty much the same way. When users find it in the documentation, they may expect an Option::xor as well. If OCaml and Haskell also have an equivalent method to Option::or, but not a xor counterpart, it would be interesting to know why.

  2. Option::xor is a zero-cost abstraction, which is a valued concept in Rust. It's a tool that allows programmers to do more with less code. But if you don't need to use it, you have no penalties. The footprint of Option::xor in the standard library is also very small. #50553 adds only 36 lines, most of which are documentation comments.

  3. Users cannot implement this method in their own crates, as the Option type doesn't belong to them. The alternatives I can think of are a bit cumbersome, or at least not as convenient:

    • Use a match directly
    • Create a function similar to fn option_xor<T>(opta: Option<T>, optb: Option<T>) -> Option<T>
    • Create a new trait and implement Option::xor inside it
  1. Rust already has a stable Option::or method, which works pretty much the same way. When users find it in the documentation, they may expect an Option::xor as well. If OCaml and Haskell also have an equivalent method to Option::or, but not a xor counterpart, it would be interesting to know why.

Haskell's standard library has the more general operation <|>:

class Applicative f => Alternative f where 
  empty :: f a
  (<|>) :: f a -> f a -> f a

and Maybe is an instance of Alternative.

Haskell's standard library has the more general operation <|>:

class Applicative f => Alternative f where
empty :: f a
(<|>) :: f a -> f a -> f a

and Maybe is an instance of Alternative

Looking at the implementation, it seems that Haskell's implementation is an inclusive or rather than exclusive and takes the first argument if it's present regardless of the second.

The final comment period, with a disposition to merge, as per the review above, 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.

The RFC will be merged soon.

@Amanieu & @withoutboats: Since you have expressed doubts, can you confirm that you are OK with moving forward with this?

Was this page helpful?
0 / 5 - 0 ratings