I added a PR for lossless float to int conversions as
TryFrom impls, the intent was for these to fail unless a float represents exactly the number it is being converted to and fits within the destination type. At the time I did not deem it complex enough to warrant an RFC, just another impl of
During discussion it was raised by @rkruppe that these float conversions might be too special to put into
TryFrom, so I’m raising the discussion here to gather more feedback from the community.
I would like to pose the following questions:
- Through which mechanism should fallible float-to-int conversions be provided?
- Should the default conversion (provided through
TryFrom) coerce* the value in any way?
*: See the discussion regarding rounding policy below for options.
I’m reproducing the last comment I had in the PR since I think it’s useful for more context. This briefly discusses which rounding policy should be used for default conversion, and whether
TryFrom should only provide lossless conversions in std.
Which rounding policy should be used?
Some GitHub searching results in:
trunc() as, 132 occurrences.
round() as, 172 occurrences.
ceil() as, 371 occurrences.
floor() as, 260 occurrences.
Note that since casting floats in Rust is unsound #10184, the cases which cast (and trunc) might not constitute an active choice. More “do something which makes this an integer”. This limited dataset leads me to believe that picking one policy runs the risk of making a large fraction of the community unhappy about the choice.
Making the conversion fail on inexact values can be a hint to the user that they should pick. This would be unfortunate to do at runtime, which would speak for instead having specialized conversion methods for floats (
f32::to_i32_exact through a trait like
Outside of casting (which generally truncs), other strongly typed languages seem to force you to actively pick your policy as well.
From/TryFrom has been lossless so far
Many (all?) of the std trait implementations are lossless. Rounding a float is primarily a way to make members of one type fit into another. A similar but more extreme example of this would be to clampen or project an integer which is to wide to fit into a narrower sibling. The existing conversion methods do not attempt to “coerce” types in this manner.
It’s unfortunate that this is not stated clearly, since we are now having to deal with what users would expect out of the conversion traits, which is hard to quantify. But float conversions might also be so special that “lossless conversion” isn’t meaningful enough to warrant inclusion through
My personal observation is that the existing fallible conversion methods fail when information would otherwise be lost.