-
Notifications
You must be signed in to change notification settings - Fork 20
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
ACP: primitive numeric traits #371
Comments
don't forget shifts by and conversions from/to |
Additional note: having these traits in the prelude (although probably |
It seems non-intuitive to me to require all of these implementations together in a single trait. Mostly, I'm eyeing
It is my experience that these are the most likely to be inference-breaking in many cases. While T-libs-api is I am sure thinking about this sort of thing often, I think it would be good to discuss the logistics of bound-selection here, given that bounds get implied in some cases and not in others, which means in some cases relaxing a bound is in fact API-breaking, if memory serves. And I mention this because we may wish to add a novel Not "why these picks", I mean, more "what to keep in mind when making these picks". |
Added those to the ACP and the draft PR, as well as a few that were already available in the PR but not the ACP.
The current
I know you said you aren't asking "why" but the response is to clarify "why:" it's supposed to encompass all of the (elaboratable) bounds satisfied by all of the primitive numeric types and whose definition is width-independent, meaning that supplying the functionality for new That said, any of this API surface potentially not making sense to provide for a future Also note that I only included |
I wonder if, like with That would allow handling the "I just wanted to implement it for the types" in a way that's directly allowed with coherence because |
like rust-lang/rfcs#2581? I was just mentioning on Zulip that Rust is falling behind C/C++ which already have |
We discussed this in the libs-api meeting yesterday. The overall feeling was that it introduces a rather large API that duplicates the existing inherent methods and it's not clear why this specifically needs to be in the standard library when crates like |
Primarily, for coherence reasons. Because the traits are marked Secondarily, for optics reasons. These type sets are the most obvious ones to generalize code over, and the inability to write code generic over integer width without macros is not infrequently cited as a failing of Rust. A solution that made If libs-api thinks the language approach without the trait is a preferable direction to explore, then this can be closed in favor of that. |
Biased as the author of rust-lang/rfcs#2581, but I also would be largely in favour of having generic Floats are… way more complicated and would be much less likely to support generics. Especially if we consider floating-point formats like Perhaps a generic I'm not trying to design the full feature here for floats, but want to express the likely path any design would take, so that it can be compared for complexity with a trait. For integers, the decision feels obvious to me, with a generic type being the better path, but the added complexity for floats certainly changes things on that camp. Additionally, if we do assume that all of the proposed float types get stabilised, it would put the number of them similar to the existing integer types, with We can also consider "weird" floating-point types like Something that would generalise over all float types including something like |
I'm all for having generic integer types, but I don't think that means we can't have integer traits too, since abstracting over signed/unsigned and
agreed, though |
Incredibly fair, although IMHO the question of whether you should implement a trait for
Oh, I actually had no idea this was the case. In that sense, it would probably still count as a "weird" float type, since it doesn't behave the same as the IEEE 754 types. IMHO, generalising over all these different variables on floats is exactly the kind of thing we'd like to avoid, since there are all kinds of parameters you could control like how the bias works, whether subnormal numbers exist, NaN behaviour, etc., but you really shouldn't, because floating-point semantics are already a mess and we should at least agree on what the bits mean. |
well, actually it does behave almost exactly like an IEEE 754 type with 1 sign bit, 15 exponent bits, and 63 mantissa bits, except that there's an extra bit that's usually 1 (0 for denormals), but you can have unnormalized mantissas, and NaNs use all 64-bits of the mantissa. so it very much is a floating-point type, not integer. |
Yeah, that was 100% just me misspeaking; please carry on. The extra bit making the difference between how subnormals work is substantial enough a difference to make it different from other float types, IMHO. |
Having had some more time to think about it, I'm now shifting much more firmly into thinking that turning IEEE defines what the Generalization to both signed and unsigned, to include I'm going to leave this open until there's an RFC to point to (or t-libs opts to close it) for the time being, though, since I still strongly believe the underlying need is legitimate, even if this specific API isn't the best way to address it. |
Proposal
Problem statement
Rust developers, especially those coming from a C++-ish background, often want to write code which is generic over the different primitive numeric types (i.e.
iNN
,uNN
,fNN
). That this can't be done without usingmacro_rules!
to paste a trait implementation across has been called "inelegant," and not uncommonly results in beginners trying what seems like an "obvious" axis for generalization being told "you can't do that" for reasons unrelated to what they're trying to accomplish.The various ecosystem crates for numeric abstraction (e.g. num-traits, funty) clearly illustrate that the desire exists. This ACP doesn't aim to be the final solution, but offers a conservative step forward to solve a clearly defined subset of the problem that will remain useful even if a more general abstraction is added in the future.
Solution sketch
Specifically, we add two sealed and fundamental traits to
core::primitive
which capture exactly the set of types in the pseudo-types{integer}
and{float}
(the types given to integer and float literals before type inference). By virtue of being sealed and restricting semantics to just the primitive numeric types, the API signature that should be available on the trait is relatively straightforward — the API which already already exists macro-pasted over each of the primitive numeric types. These traits can be expanded in future releases to expose added inherent functionalityPer this, listed below is just what functionality is simple to add right now and is intended to be further extended.
In the future, an extension to coherence that would allow
impl<T: Integer> Trait for T
andimpl<T: Float> Trait for F
to be known non-overlapping (e.g. equivalent to using theimpl
headers for the fundamental trait bound) could makeAlternatives
Doing nothing in std and leaving it to ecosystem crates to provide this functionality is a valid option, and has worked so far.
Instead of using a single trait with both bounds and methods, it could be beneficial to put methods on one trait and expose
Integer
/Float
as trait aliases which include the bound on method availability and all of the other traits. The trait alias form would be able to provide additional&Self: Op<&Self, Output = Self>
bounds (while still getting them elaborated at use sites) as well as enable downstreams that want less ambiguous inference around e.g. shifts or conversions to specify fewer bounds.Splitting methods/bounds has potential technical benefits, but I don't see splitting the functionality further (e.g. to extract a shared supertrait) as being particularly beneficial. Even additional
SignedInteger
/UnsignedInteger
subtraits seem difficult to justify; the goal is not to create a robust modelling of algebraic fields (that would be delegated to ecosystem crates, e.g. num-traits, alga, or simba), but solely to enable the "obvious" generalization over the primitive numeric types that would otherwise have to be done with macros.Links and related work
What happens now?
This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.
Possible responses
The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):
Second, if there's a concrete solution:
The text was updated successfully, but these errors were encountered: