Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add const inherent comparison methods to integers. #68557

Closed
CDirkx opened this issue Jan 26, 2020 · 1 comment
Closed

Add const inherent comparison methods to integers. #68557

CDirkx opened this issue Jan 26, 2020 · 1 comment

Comments

@CDirkx
Copy link
Contributor

CDirkx commented Jan 26, 2020

Const comparisons

Goal: Compare values inside const contexts.

Most common cases of comparison logic:

  • primitive comparison
  • comparison by key
  • lexicographical comparison by multiple keys
  • comparison by order (enums)

When #[feature(const_if_match)] (#49146) lands almost all comparison logic could be const.

Problem

Most types that can be compared just derive or implement PartialOrd and Ord. However, as trait methods cannot be const (maybe in the far future if we have const traits), the logic inside these cmp and partial_cmp methods is unavailable in const contexts.

The only exceptions to this are the >, <, >=, <= operators for some primitives: floating-point numbers, integers, bool, char and !, which are (I think) const intrinsics. Note that these operators all result in a bool, there is no const comparison function resulting in a std::cmp::Ordering. This makes custom const lexicographical comparisons still hard to write compared to using std::cmp::Ordering::then (also not yet const).

Proposal

Add a const inherent comparison method to applicable types and let the Ord and PartialOrd delegate to this method:

impl T {
  pub const fn cmp(&self, other: &T) -> std::cmp::Ordering { 
    ...
  }
}

impl Ord for T {
  fn cmp(&self, other: &T) -> std::cmp::Ordering {
    self.cmp(other)
  }
}

impl PartialOrd for T {
  fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
    Some(self.cmp(other))
  }
}

As a conservative implementation, only implement a const comparison method for integers first. The operators >, <, >= and <= are already const for these types. Together with making std::cmp::Ordering::then const this will make doing a lexicographical on integer fields easier inside a const context.

After implementation for integers const comparison methods could be added to floating-point numbers and other primitives. Later more complex types could also be extended.

Implementation

  1. Wait for stabilization of #[feature(const_if_match)] (Tracking issue for RFC 2342, "Allow if and match in constants" #49146).
  2. Add const comparison methods to integers (under Tracking Issue for more const int functions #53718).
  3. Make std::cmp::Ordering::then const.
  4. Decide on other types to implement a const comparison method for.

Drawbacks / open questions

  1. Any comparisons involving generics like Vec<T> or (T, U) requires traits and can thus not be made const with this proposal.
    • The comparison of a type like String, which internally uses a Vec<u8>, could technically be const, just by special casing and by not relying on a generic Vec comparison implementation.
    • The same goes for any composition of primitives, such as arrays and tuples. This would however require even more special cases.
  2. Name of the method: cmp? This would shadow the Ord trait, does that lead to complications? Alternative: compare, ...

Alternatives

  1. Leave situation as is: >, <, <= and >= are already const for integers, thus a const cmp(self, other) -> std::cmp::Ordering does not pull it's weight to necessitate an addition to the standard library.
    1. Wait for const traits and make a const version of Ord and PartialOrd,
    2. Wait for const trait methods and make Ord::cmp and PartialOrd::partial_ord const (breaking change).
    3. If really necessary a local const helper method can easily be written by a user: const fn cmp(a: u8, b: u8) -> Ordering { if a < b { Less } else if a == b { Equal } else { Greater } }
@jonas-schievink
Copy link
Contributor

rust-lang/rfcs#2632 would address this, so closing in favor of that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants