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

FixedDecimal mutating functions should use active verbs #2902

Closed
sffc opened this issue Dec 19, 2022 · 20 comments · Fixed by #5242
Closed

FixedDecimal mutating functions should use active verbs #2902

sffc opened this issue Dec 19, 2022 · 20 comments · Fixed by #5242
Assignees
Labels
2.0-breaking Changes that are breaking API changes A-design Area: Architecture or design C-numbers Component: Numbers, units, currencies

Comments

@sffc
Copy link
Member

sffc commented Dec 19, 2022

It occurred to me when reviewing #2898 that the function names we chose for rounding do not have an active verb: "half_even", etc. Should they be active verbs?

Some of the functions are fine, like "trunc". I feel like "floor" is understood to be a verb in this context, too.

@sffc sffc added discuss Discuss at a future ICU4X-SC meeting 2.0-breaking Changes that are breaking API changes labels Dec 19, 2022
@eggrobin
Copy link
Member

eggrobin commented Dec 19, 2022

Some of the functions are fine, like "trunc".

I must say trunced makes me think of trounced than truncated (but agreed, it is more understandable than the various flavours of rounding to nearest).

@sffc sffc added the C-numbers Component: Numbers, units, currencies label Dec 22, 2022
@sffc
Copy link
Member Author

sffc commented May 25, 2023

Discuss with:

@sffc sffc added the discuss-triaged The stakeholders for this issue have been identified and it can be discussed out-of-band label May 25, 2023
@skius
Copy link
Member

skius commented May 26, 2023

Some thoughts: I think there's nothing majorly wrong with the current way. If we wanted to change it, here's some suggestions:

  • apply_ as prefix for the unit methods, and the current unit names for the chaining methods, e.g., apply_half_trunc(mut &self); and half_trunc(self).
  • _chain (or _chained) suffix for the chaining methods, e.g., half_trunc(&mut self) and half_trunc_chain(self).

Another thought, however, is that I had some trouble understanding all the methods (e.g., half_even and half_expand) from their names and their docs. After realizing that we're in the context of rounding, half_even was clear after consulting the wikipedia article on Rounding. There's nothing in the article about "half expand" (or "expand", for that matter), however, and even checking the first few Google results for "half expand rounding" doesn't explain what it is. I assume it is the same as f64::round, i.e., "rounding away from zero".

Since we are discussing changing names, maybe adding a round somewhere in the name might help, and it could also turn the name into an active verb. But otherwise, because the crate is essentially only used internally, I don't think this is actionable enough to open an issue/change the docs (unless other people strongly agree).

Verdict: I don't think the issue of active verbs is a big deal, but changing names might clear things up a bit. I do agree with @eggrobin that trunc/truncate is a commonly understood name for that specific kind of rounding.

@sffc
Copy link
Member Author

sffc commented Jul 7, 2023

  • @eggrobin - "expand" came out of nowhere.
  • @sffc - (discusses history of how ECMA arrived at it)
  • @Manishearth - We could provide both "away_from_zero" and "expand" as function names
  • @younies - Following the standardization, even from ECMA, seems better than inventing a new name
  • @sffc - We have ECMA in our charter so I think it is fine to follow ECMA. If we have long names, they should be for everything.
  • @eggrobin - The ECMA decision was in a desire for short identifiers which may not be shared by this project. I would agree with long names for everything.
  • @Manishearth - We do have some pressure toward small identifiers, but it is not strong
  • @Manishearth - We rely on ECMA for scope and operations, and we take inspiration for API from there but also ICU, etc. It's going to take a while for "expand" to peculate through even the ECMA community. We should have API names that make sense for Rust people and people in other programming languages. "expand" is a choice that doesn't make sense with intuition.
  • @sffc - Adding these APIs is 18 more functions.
  • @sffc - "expand" is the only short name in the industry for this operation.
  • @sffc - It's doing a positive service by evangelizing this word; it helps make it a consistent word and makes it in effect more horizontal.
  • @eggrobin - IEEE 754 is very horizontal
  • @Manishearth - We could go all in on the long names and deprecate all the short names... my priority order is to fix confusion in the API
  • @skius - Java uses the word "up"
  • @sffc - It's not clear that this is confusing. If the function's docs are not clear, we should just make them more clear. I don't think the new information we have from 1.0 is enough to justify backtracking.
  • @sffc - IEEE 754 does not list all 9 rounding modes; only a subset
  • @eggrobin - It is an extensible scheme
  • @skius - Rust uses "round" for expand
  • @Manishearth - It's confusing but makes sense if you're only exposing 3
  • @sffc - I would not be opposed to an API named "round" aliasing to half_expand
  • @Manishearth - Yeah maybe in Rust only
  • @eggrobin - That seems like it adds to the pile of confusing APIs

Conclusion: Add better documentation for FixedDecimal. We are unable to reach consensus on a set of names for the functions.

@sffc sffc added A-design Area: Architecture or design and removed discuss Discuss at a future ICU4X-SC meeting discuss-triaged The stakeholders for this issue have been identified and it can be discussed out-of-band labels Jul 7, 2023
@sffc sffc added this to the Backlog ⟨P4⟩ milestone Jul 7, 2023
@sffc
Copy link
Member Author

sffc commented Jul 7, 2023

A slate of names to consider in the future (suggested by @eggrobin):

  • round_ceiling
  • round_flooring
  • round_expanding
  • round_truncating
  • round_half_ceiling
  • ...
  • rounded_ceiling
  • ...

@sffc sffc modified the milestones: Backlog ⟨P4⟩, ICU4X 2.0 Feb 12, 2024
@sffc
Copy link
Member Author

sffc commented Feb 12, 2024

With the addition of @jedel1043's new RoundingIncrement functions, @markusicu noted that the matrix of these rounding functions is very large and unwieldy. I believe we now have 36 rounding functions, 4 for each of the 9 rounding modes.

We need separate *_to_increment because of code size. However, we could reduce the matrix by eliminating the self-moving function variants, since this can be fairly ergonomically modeled using Rust code blocks.

Also incorporating @eggrobin's naming scheme from the previous post, it would mean clients would need to change the following:

formatter.format(
    FixedDecimal::from(123usize)
        .multiplied_pow2(-2)
        .half_expanded(-1))

to

formatter.format({
    let mut fd = FixedDecimal::from(123usize);
    fd.multiply_pow2(-2);
    fd.round_half_expanded(-1);
    fd
})

Of course the assembly code between these two examples should be exactly the same.

@sffc
Copy link
Member Author

sffc commented Feb 13, 2024

Seeking consensus on the following proposals for 2.0:

Part 1

Remove the self-moving rounding functions in order to reduce API bloat. See previous post.

Seeking consensus from:

Part 2

Rename all of the rounding functions to have round_* in the name, and fully spell out their English names. The full list:

  • round_ceiling(&mut self, position: i16)
  • round_ceiling_to_increment(&mut self, position: i16, increment: RoundingIncrement)
  • round_half_ceiling(&mut self, position: i16)
  • round_half_ceiling_to_increment(&mut self, position: i16, increment: RoundingIncrement)
  • round_flooring(&mut self, position: i16)
  • round_flooring_to_increment(&mut self, position: i16, increment: RoundingIncrement)
  • round_half_flooring(&mut self, position: i16)
  • round_half_flooring_to_increment(&mut self, position: i16, increment: RoundingIncrement)
  • round_truncating(&mut self, position: i16)
  • round_truncating_to_increment(&mut self, position: i16, increment: RoundingIncrement)
  • round_half_truncating(&mut self, position: i16)
  • round_half_truncating_to_increment(&mut self, position: i16, increment: RoundingIncrement)
  • round_expanding(&mut self, position: i16)
  • round_expanding_to_increment(&mut self, position: i16, increment: RoundingIncrement)
  • round_half_expanding(&mut self, position: i16)
  • round_half_expanding_to_increment(&mut self, position: i16, increment: RoundingIncrement)
  • round_half_even(&mut self, position: i16)
  • round_half_even_to_increment(&mut self, position: i16, increment: RoundingIncrement)

Seeking consensus from:

Part 3

To increase discoverability, add aliases for the most common rounding functions:

  • floor == round_flooring
  • ceil == round_ceiling
  • trunc == round_truncating
  • expand == round_expanding
  • round == round_half_even

Seeking consensus from:

Part 4 Alternative A

To further reduce API bloat but at the cost of choices when it comes to code size, we can make all round_* functions take a RoundingIncrement. This proposal is contingent on Part 3 being approved: those functions will not take a RoundingIncrement parameter and thereby get optimal code size.

  • round_ceiling(&mut self, position: i16, increment: RoundingIncrement)
  • round_half_ceiling(&mut self, position: i16, increment: RoundingIncrement)
  • round_flooring(&mut self, position: i16, increment: RoundingIncrement)
  • round_half_flooring(&mut self, position: i16, increment: RoundingIncrement)
  • round_truncating(&mut self, position: i16, increment: RoundingIncrement)
  • round_half_truncating(&mut self, position: i16, increment: RoundingIncrement)
  • round_expanding(&mut self, position: i16, increment: RoundingIncrement)
  • round_half_expanding(&mut self, position: i16, increment: RoundingIncrement)
  • round_half_even(&mut self, position: i16, increment: RoundingIncrement)

Seeking consensus from:

Part 4 Alternative B

To reduce API bloat even further, we can merge all of the "unusual" rounding functions down to just one function that takes an enumeration argument.

Again, this is dependent on Part 3 so that we provide something for code-size-conscious clients.

There is some bikeshedding to do here. A strawperson:

pub enum RoundingMode {
    Ceil,
    Floor,
    Trunc,
    Expand,
    HalfCeil,
    HalfFloor,
    HalfTrunc,
    HalfExpand,
    HalfEven,
}

impl FixedDecimal {
    pub fn round_to_mode(&mut self,
        position: i16,
        mode: RoundingMode) { ... }

    pub fn round_to_mode_and_increment(&mut self,
        position: i16,
        mode: RoundingMode,
        increment: RoundingIncrement) { ... }
}

Seeking consensus from:

@sffc sffc added the needs-approval One or more stakeholders need to approve proposal label Feb 13, 2024
@sffc
Copy link
Member Author

sffc commented Feb 13, 2024

As part of this issue, we should also address the documentation feedback @markusicu left in the RoundingIncrement API Review here: https://docs.google.com/document/d/1gKZCaiTG2eeyxrIKUF2tf6PIsaPCIBaUVRXD-JDh6dI/edit#heading=h.7pm5mstzwo40

@jedel1043
Copy link
Contributor

jedel1043 commented Feb 13, 2024

Agreed on the general idea of parts 1-3. For part 4, I strongly tend towards B because it would considerably simplify the API usage for users who take the rounding mode programmatically. Example of the current usage:

https://github.com/boa-dev/boa/blob/7da0f270cd8582fb030a4816775f7944acd5c2b2/core/engine/src/builtins/intl/number_format/options.rs#L722-L739

match mode {
    RoundingMode::Ceil => number.ceil_to_increment(position, multiple),
    RoundingMode::Floor => number.floor_to_increment(position, multiple),
    RoundingMode::Expand => number.expand_to_increment(position, multiple),
    RoundingMode::Trunc => number.trunc_to_increment(position, multiple),
    RoundingMode::HalfCeil => number.half_ceil_to_increment(position, multiple),
    RoundingMode::HalfFloor => number.half_floor_to_increment(position, multiple),
    RoundingMode::HalfExpand => number.half_expand_to_increment(position, multiple),
    RoundingMode::HalfTrunc => number.half_trunc_to_increment(position, multiple),
    RoundingMode::HalfEven => number.half_even_to_increment(position, multiple),
}

With the proposed change, this would simplify to:

number.round_to_mode_and_increment(position, mode, multiple)

@markusicu
Copy link
Member

I don't feel strongly about the round_ prefix, but the suffixes that follow bother me. "ceiling" is a noun, something to round towards. "truncating" is the infinitive of a verb. "flooring" sounds like a known (as in a flooring store), but I suspect that you intend it to be understood as another verb infinitive. And adding "-ing" would be comical on "half_even".

@markusicu
Copy link
Member

On Alternative B, you could drop the _to_mode suffix/infix.

@sffc
Copy link
Member Author

sffc commented Feb 13, 2024

On Alternative B, you could drop the _to_mode suffix/infix.

My proposal is that round performs default half-even rounding, which means we need some other name for the function that takes the RoundingMode argument.

@jedel1043
Copy link
Contributor

My proposal is that round performs default half-even rounding

This is consistent with Python, but I think it's more common to use half-expand rounding by default. (Rust uses that in its f32/f64::round method).

@sffc
Copy link
Member Author

sffc commented Feb 13, 2024

My proposal is that round performs default half-even rounding

This is consistent with Python, but I think it's more common to use half-expand rounding by default. (Rust uses that in its f32/f64::round method).

Okay, how about making the list of functions in Part 3 be

  • (ceil, floor, trunc, expand)
  • round_half_even
  • round_half_expand

I would like to not add a function named round that takes a large matrix of arguments due to code size and performance. Better to have users who need the extra power "opt in" by using a longer function name.

@eggrobin
Copy link
Member

eggrobin commented Feb 13, 2024

Scripsit Markus:

the suffixes that follow bother me. "ceiling" is a noun, something to round towards. "truncating" is the infinitive of a verb. "flooring" sounds like a known (as in a flooring store), but I suspect that you intend it to be understood as another verb infinitive. And adding "-ing" would be comical on "half_even".

4B does have the advantage of sidestepping the whole discussion of how to avoid silliness of either round half evenings or round half floors (presumably these are found in half-apartments of spherical buildings?), while retaining the word round that gives the hapless reader a chance to figure out what this mysterious evening is about1.

Footnotes

  1. As partially captured in the minutes from last summer I still think it was a dreadful idea not to go with the decades-old round (to nearest ties )?(away from 0|towards (0|(positive|negative) infinity)|to (odd|even)) which is standard throughout the numerical analysis literature, but at least with the word round one knows that one needs to map to that.

@Manishearth Manishearth moved this to Tiny (can be done near the end) in icu4x 2.0 Feb 23, 2024
@Manishearth Manishearth moved this from Tiny (can be done near the end) to Unclaimed for sprint in icu4x 2.0 Feb 23, 2024
@Manishearth
Copy link
Member

Can be done pre-2.0 because fixed_decimal is not icu4x-versioned

@robertbastian robertbastian moved this from Unclaimed for sprint to Small breakage (defer to end) in icu4x 2.0 Mar 6, 2024
@sffc sffc removed the needs-approval One or more stakeholders need to approve proposal label Mar 14, 2024
@sffc
Copy link
Member Author

sffc commented Mar 14, 2024

It is in FFI and therefore impacts 2.0

@sffc
Copy link
Member Author

sffc commented Jun 3, 2024

My understanding is that the proposed set of functions is:

  • ceil(position)
  • floor(position)
  • trunc(position)
  • expand(position)
  • either round(position) or round_half_even(position)
  • optional round_half_expand(position)
  • round_with_mode(RoundingMode, position)
  • round_with_mode_and_increment(RoundingMode, position, RoundingIncrement)

Does that match everyone's expectations?

@sffc
Copy link
Member Author

sffc commented Jun 3, 2024

Also, do we still keep the -ed versions?

With fewer functions, maybe we can afford to keep them now.

@sffc
Copy link
Member Author

sffc commented Jun 6, 2024

Start: 11:05

  • @sffc - I had suggested removing the self-moving functions earlier, but now that we will have many fewer rounding functions, maybe we can keep them because the matrix is not as big.
  • @robertbastian - &mut self functions are annoying to work with, I'd prefer keeping them

Conclusion: keep self-moving functions.

@sffc @robertbastian

sffc pushed a commit that referenced this issue Jun 26, 2024
Related to #2902

Mainly removes all the `_to_increment` methods, which are superseeded by
the `round_with_mode_and_increment` method.

Additionally, adds a `round` function that does half to even rounding.
@sffc sffc closed this as completed in 33bbe03 Jul 15, 2024
@github-project-automation github-project-automation bot moved this from Small breakage (defer to end) to Done in icu4x 2.0 Jul 15, 2024
blaynem pushed a commit to blaynem/icu4x that referenced this issue Jul 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.0-breaking Changes that are breaking API changes A-design Area: Architecture or design C-numbers Component: Numbers, units, currencies
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

6 participants