Skip to content

Tracking issue for Option::xor #50512

@andre-vm

Description

@andre-vm
Contributor

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.

Activity

changed the title [-]Add `xor` method to `Option<T>`[/-] [+]Add xor method to Option<T>[/+] on May 7, 2018
added
T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.
C-feature-requestCategory: A feature request, i.e: not implemented / a PR.
on May 7, 2018
clarfonthey

clarfonthey commented on May 7, 2018

@clarfonthey
Contributor

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

ollie27

ollie27 commented on May 7, 2018

@ollie27
Member

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

clarfonthey

clarfonthey commented on May 8, 2018

@clarfonthey
Contributor

…good point. Never mind, then.

added a commit that references this issue on May 17, 2018
0c0bb18
andre-vm

andre-vm commented on May 18, 2018

@andre-vm
ContributorAuthor

Implemented on #50553.

clarfonthey

clarfonthey commented on May 18, 2018

@clarfonthey
Contributor

@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.

added
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
and removed
C-feature-requestCategory: A feature request, i.e: not implemented / a PR.
on May 18, 2018
changed the title [-]Add xor method to Option<T>[/-] [+]Tracking issue for Option::xor[/+] on May 18, 2018

19 remaining items

lambda-fairy

lambda-fairy commented on Mar 1, 2019

@lambda-fairy
Contributor

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.

andre-vm

andre-vm commented on Mar 1, 2019

@andre-vm
ContributorAuthor

@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. Add Option::xor method #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
Centril

Centril commented on Mar 1, 2019

@Centril
Contributor
  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.

boomshroom

boomshroom commented on Mar 1, 2019

@boomshroom

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.

rfcbot

rfcbot commented on Mar 5, 2019

@rfcbot
Collaborator

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.

added and removed
final-comment-periodIn the final comment period and will be merged soon unless new substantive objections are raised.
on Mar 5, 2019
Centril

Centril commented on Mar 5, 2019

@Centril
Contributor

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

added
E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.
on Mar 26, 2019
added 2 commits that reference this issue on Jun 12, 2019
aaditmshah

aaditmshah commented on May 15, 2023

@aaditmshah

@andre-vm I just wanted to point out that Option::xor is not associative.

  lhs
= Some(1).xor(Some(2)).xor(Some(3))
= None.xor(Some(3))
= Some(3)

  rhs
= Some(1).xor(Some(2).xor(Some(3)))
= Some(1).xor(None)
= Some(1)

However, boolean xor is associative.

  lhs
= (true != true) != true
= false != true
= true

  rhs
= true != (true != true)
= true != false
= true

Thus, it seems to me that Option::xor is not an exclusive or operation (over a functor) in the strictest sense. Nevertheless, it still seems to be a useful operation. Hence, I would suggest adding a remark to the documentation, elucidating that Option::xor is not associative.

aaditmshah

aaditmshah commented on May 15, 2023

@aaditmshah

I would also like to point out a simpler operation than Option::xor, which can be used to implement Option::xor:

impl<T> Option<T> {
    fn and_not<U>(self, other: Option<U>) -> Option<T> {
        match &other {
            &None => self,
            _ => None,
        }
    }
}

The Option::xor operation can be implemented using a combination of Option::and_not and Option::or.

option_a.xor(option_b) = option_a.and_not(option_b).or(option_b.and_not(option_a))

Conversely, we can implement Option::and_not using a combination of Option::xor and Option::and.

option_a.and_not(option_b) = option_a.map(Ok).xor(option_b.map(Err)).and(option_a)

It would be nice to have Option::and_not in the core library. However, even if we don't have it, it would be nice to add the previous example to the documentation of Option::xor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    B-unstableBlocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCE-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @cuviper@kennytm@Amanieu@boomshroom@pravic

      Issue actions

        Tracking issue for Option::xor · Issue #50512 · rust-lang/rust