From 32be998e5c5b687ae43ba22f72198f1d4bff6800 Mon Sep 17 00:00:00 2001 From: Victor Polevoy Date: Thu, 21 Dec 2017 10:56:31 +0300 Subject: [PATCH 1/2] Create 0000-add-limits-trait.md --- text/0000-add-limits-trait.md | 133 ++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 text/0000-add-limits-trait.md diff --git a/text/0000-add-limits-trait.md b/text/0000-add-limits-trait.md new file mode 100644 index 00000000000..cbd3c86b131 --- /dev/null +++ b/text/0000-add-limits-trait.md @@ -0,0 +1,133 @@ +- Feature Name: Limits trait for the rust types +- Start Date: 2017-12-20 +- RFC PR: +- Rust Issue: + +# Summary +This is an RFC to add a universal trait for the type limits. + +# Motivation +The motivation is quite simple: [make an ability to accept template types with with limits by requiring a trait](https://stackoverflow.com/questions/47904954/rust-finding-the-maximum-allowable-value-for-generic-data-type-t) +so that it simplifies and generalizes the code. Another motivation is that we have all that `max_value()` and `min_value()` implemented as +usual methods of a type implementation, generalizing this to a trait makes the code simplier and avoids duplicating code. Also, looking at +C++ template of `std::numeric_limits` tells us we must have this thing too because it is easier to use. + +# Detailed design +The design is quite simple: put everything related to the limits what can be generalized into a separate trait in the standard library: + +```rust +trait Limits { + fn min_value() -> T; + fn max_value() -> T; +} + +#[derive(Debug, Copy, Clone)] +struct A { + field: u64, +} +impl Limits for A { + fn min_value() -> A { + A { + field: 0u64, + } + } + + fn max_value() -> A { + A { + field: 5u64, + } + } +} +impl Limits for u32 { + fn min_value() -> u32 { + 0 + } + fn max_value() -> u32 { + 10u32 + } +} + +fn get_limits + std::fmt::Debug>(_t: T) { + println!("Minimum value: {:?}", T::min_value()); + println!("Maximum value: {:?}", T::max_value()); +} + +fn main() { + let a = A { field: 6u64 }; + let num = 10u32; + get_limits(a); + get_limits(num); +} + +``` + +Here we have a generalized function `get_limits` which accepts its argument with requirement for trait `Limits` implementation. As long +as a type implements this trait, this function will succeed and will produce expected results. It's worth mentioning that a type can implement +different limits type, not only for itself: `struct A` can have both `Limits` and `Limits` implementations: we may simply add another +implementation and use it in our generalized function appropriately: + +```rust +impl Limits for A { + fn min_value() -> u32 { + 0u32 + } + + fn max_value() -> u32 { + 5u32 + } +} + + +/// Will be called only if a type implements Limits with u32 value type. +fn get_limits + std::fmt::Debug>(_t: T) { + println!("Minimum value: {:?}", T::min_value()); + println!("Maximum value: {:?}", T::max_value()); +} +``` + +Another option is to use the [`Bounded`](http://rust-num.github.io/num/num/trait.Bounded.html) trait of `num` crate: + +```rust +trait Limits { + fn min_value() -> Self; + fn max_value() -> Self; +} +``` + +This will reduce the ambiguity of types and in most cases will be enough too. + +# How We Teach This +I think the `Limits` name of a trait is appropriate: +- `numeric_limits` is incorrect since the trait may be implemented for any type and it may be not numerical. +- `Bounds` does not seem to be appropriate (personally for me). + +This feature does not involve anything into the language itself, but adds a trait into the standard library. All the primitive types +and anything else what has `min_value()` and `max_value()` methods must implement this trait. Removing the type method is not required +(why does it work with having both a trait implementation and a type method - I don't know). + +This feature can be introduced as `Limits` trait for the generalized contexts. + +# Drawbacks +I don't know why we should not do this. + +# Alternatives +Another option is to simply add macros for this: + +```rust +macro_rules! max_value { + ($type: ident) => { + $type::max_value() + } +} + +macro_rules! min_value { + ($type: ident) => { + $type::min_value() + } +} +``` + +This helps in generalizing the code too, but not in a way that the trait does. + +# Unresolved questions +The trait design is arguable and is ready to accept any critic, namely what is better: generic trait or a simple one. From c02436bcfb83d2c2c24b4a07822897148c4159e4 Mon Sep 17 00:00:00 2001 From: Victor Polevoy Date: Sat, 20 Jan 2018 12:58:34 +0300 Subject: [PATCH 2/2] Update 0000-add-limits-trait.md --- text/0000-add-limits-trait.md | 176 +++++++++++----------------------- 1 file changed, 56 insertions(+), 120 deletions(-) diff --git a/text/0000-add-limits-trait.md b/text/0000-add-limits-trait.md index cbd3c86b131..6d2c18acb09 100644 --- a/text/0000-add-limits-trait.md +++ b/text/0000-add-limits-trait.md @@ -1,133 +1,69 @@ - Feature Name: Limits trait for the rust types - Start Date: 2017-12-20 -- RFC PR: -- Rust Issue: +- RFC PR: +- Rust Issue: # Summary -This is an RFC to add a universal trait for the type limits. +[summary]: #summary + +This is an RFC to add a universal trait for the type limits. This is needed because at the moment of writing it is not +possible to abstract types which have limits. This could be done with using generic types or trait objects, but since +the `min()` and `max()` functions are not in a separate trait it is not possible. Also, providing a trait for this adds +possibility to implement it for any type and so use the limits abstractions with any type, not just ones we already have. # Motivation -The motivation is quite simple: [make an ability to accept template types with with limits by requiring a trait](https://stackoverflow.com/questions/47904954/rust-finding-the-maximum-allowable-value-for-generic-data-type-t) -so that it simplifies and generalizes the code. Another motivation is that we have all that `max_value()` and `min_value()` implemented as -usual methods of a type implementation, generalizing this to a trait makes the code simplier and avoids duplicating code. Also, looking at -C++ template of `std::numeric_limits` tells us we must have this thing too because it is easier to use. - -# Detailed design -The design is quite simple: put everything related to the limits what can be generalized into a separate trait in the standard library: - -```rust -trait Limits { - fn min_value() -> T; - fn max_value() -> T; -} - -#[derive(Debug, Copy, Clone)] -struct A { - field: u64, -} -impl Limits for A { - fn min_value() -> A { - A { - field: 0u64, - } - } - - fn max_value() -> A { - A { - field: 5u64, - } - } -} -impl Limits for u32 { - fn min_value() -> u32 { - 0 - } - fn max_value() -> u32 { - 10u32 - } -} - -fn get_limits + std::fmt::Debug>(_t: T) { - println!("Minimum value: {:?}", T::min_value()); - println!("Maximum value: {:?}", T::max_value()); -} - -fn main() { - let a = A { field: 6u64 }; - let num = 10u32; - get_limits(a); - get_limits(num); -} - -``` - -Here we have a generalized function `get_limits` which accepts its argument with requirement for trait `Limits` implementation. As long -as a type implements this trait, this function will succeed and will produce expected results. It's worth mentioning that a type can implement -different limits type, not only for itself: `struct A` can have both `Limits` and `Limits` implementations: we may simply add another -implementation and use it in our generalized function appropriately: - -```rust -impl Limits for A { - fn min_value() -> u32 { - 0u32 - } - - fn max_value() -> u32 { - 5u32 - } -} - - -/// Will be called only if a type implements Limits with u32 value type. -fn get_limits + std::fmt::Debug>(_t: T) { - println!("Minimum value: {:?}", T::min_value()); - println!("Maximum value: {:?}", T::max_value()); -} -``` - -Another option is to use the [`Bounded`](http://rust-num.github.io/num/num/trait.Bounded.html) trait of `num` crate: - -```rust -trait Limits { - fn min_value() -> Self; - fn max_value() -> Self; -} -``` - -This will reduce the ambiguity of types and in most cases will be enough too. - -# How We Teach This -I think the `Limits` name of a trait is appropriate: -- `numeric_limits` is incorrect since the trait may be implemented for any type and it may be not numerical. -- `Bounds` does not seem to be appropriate (personally for me). - -This feature does not involve anything into the language itself, but adds a trait into the standard library. All the primitive types -and anything else what has `min_value()` and `max_value()` methods must implement this trait. Removing the type method is not required -(why does it work with having both a trait implementation and a type method - I don't know). - -This feature can be introduced as `Limits` trait for the generalized contexts. +[motivation]: #motivation -# Drawbacks -I don't know why we should not do this. +The motivation is simple: By providing the methods in a trait, user code is able to require with a bound `X: Limit` that X has certain limits of type `Y`, which enables generic reasoning and simplifies code. + + +Another motivation is that we already have inherent methods `.max_value()` and `.min_value()` on all primitive numeric types. Generalizing those methods as a trait simplifies the code and avoids duplication. + + +Looking at other languages, C++ provides `std::numeric_limits`, while Haskell provides the `Bounded` typeclass. This provides precedent that such a facility belongs in the standard library. + + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means: -# Alternatives -Another option is to simply add macros for this: +- Introducing new named concepts. +- Explaining the feature largely in terms of examples. +- Explaining how Rust programmers should *think* about the feature, and how it should impact the way they use Rust. It should explain the impact as concretely as possible. +- If applicable, provide sample error messages, deprecation warnings, or migration guidance. +- If applicable, describe the differences between teaching this to existing Rust programmers and new Rust programmers. -```rust -macro_rules! max_value { - ($type: ident) => { - $type::max_value() - } -} +For implementation-oriented RFCs (e.g. for compiler internals), this section should focus on how compiler contributors should think about the change, and give examples of its concrete impact. For policy RFCs, this section should provide an example-driven introduction to the policy, and explain its impact in concrete terms. -macro_rules! min_value { - ($type: ident) => { - $type::min_value() - } -} -``` +The proposed feature adds a new trait to the standard library crate (`std`). The trait is called `Limits`. -This helps in generalizing the code too, but not in a way that the trait does. +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +This is the technical portion of the RFC. Explain the design in sufficient detail that: + +- Its interaction with other features is clear. +- It is reasonably clear how the feature would be implemented. +- Corner cases are dissected by example. + +The section should return to the examples given in the previous section, and explain more fully how the detailed proposal makes those examples work. + +# Drawbacks +[drawbacks]: #drawbacks + +Why should we *not* do this? + +# Rationale and alternatives +[alternatives]: #alternatives + +- Why is this design the best in the space of possible designs? +- What other designs have been considered and what is the rationale for not choosing them? +- What is the impact of not doing this? # Unresolved questions -The trait design is arguable and is ready to accept any critic, namely what is better: generic trait or a simple one. +[unresolved]: #unresolved-questions + +- What parts of the design do you expect to resolve through the RFC process before this gets merged? +- What parts of the design do you expect to resolve through the implementation of this feature before stabilization? +- What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC?