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

make more of the API const #2

Open
BurntSushi opened this issue Mar 11, 2024 · 0 comments
Open

make more of the API const #2

BurntSushi opened this issue Mar 11, 2024 · 0 comments
Labels
enhancement New feature or request

Comments

@BurntSushi
Copy link
Owner

BurntSushi commented Mar 11, 2024

While there are a smattering of useful const functions in Jiff (like Date::constant), the vast majority of all routines are not const.

When I originally set out to build Jiff, I had a goal of making as much of the crate const as possible. In theory, most APIs are "just math" and thus should be const. The only things that at least conceptually cannot be const in a datetime library are things like:

  • Determining the current time.
  • Determining the current time zone.
  • Reading time zone data from a database at runtime.

But everything else can pretty much be const. More than that, I believe const in Rust is expressive enough where one could actually write a datetime library with that sort of support today (2024-03-10).

However, despite starting with this goal, I quickly gave it up. The specific thing that caused me to give up were Jiff's internal ranged integer types. They are built in a way where they track additional state and do additional checks whenever debug_assertions is enabled. And crucially, they give half-way decent error messages when an invariant or boundary is broken. I found it incredibly difficult to make all of this work in const. Some issues I ran into:

  • While adding two i32 values via the + operator (and others) works in const Rust today, this is not supported for custom types. As far as I can tell, support for primitive operations like this is special cased in const Rust. But because traits can't be used in const Rust today, I'm not able to use operator overloading for ranged integer types. While this is technically a surmountable hurdle by simply declining to use operators, I found this to be far too annoying of a hurdle to clear. Moreover, I was unwilling to give up my specific formulation of ranged integers due to their incredible ability to provoke bugs in code that I never would have caught.
  • I found it very difficult to write nice panic error messages in const functions because none of the formatting machinery is available. This essentially means it is quite difficult to write a message that includes the troublesome value(s) and relevant boundaries. While this is also a surmountable hurdle by simply living with worse error messages, this was too big of a pill to swallow. It made diagnosing and tracking down bugs provoked by ranged integers too difficult.
  • While I mentioned this in the first bullet point, the overall inability to use traits in const Rust is a huuuuuge buzzkill. And this was especially damning in a ranged integer abstraction. In particular, ranged integers don't really want to care about their primitive representation. You want to be able to add an ri8 with an ri32 without thinking about casts or whatever. Indeed, that is their superpower. But of course, you still want to be able to specify a primitive representation so that types like Date are only 4 bytes. To make all of this work, you want impl Into<RangedIntegerTypeYouWant> everywhere. This is simply incompatible with const Rust as it exists today.

And that's just for the ranged integers. I honestly don't know what other kind of issues I'd run into, but I never really got the chance to explore it. In particular, ranged integers are such a core and fundamental part of this library's internals, that if they can't be const, then pretty much nothing can be. Indeed, even the existing const routines like Date::constant specifically need to duplicate code just to work in const Rust.

This is overall something I'd like to support, but I think const Rust needs to evolve considerably before it's compatible with the internal architecture of Jiff. In theory, Jiff could use something else that is more const friendly internally, but the hurdle it will need to clear is huge. My best guess is that it will be years before this library sees a meaningful increase in the surface area of const APIs.

I may be willing to consider one-off cases of making an API const, but the trade off will almost certainly be something like, "duplicates code and gives up ranged integers." In other words, there probably needs to be a compelling use case for it to be const. Something like Date::constant is compelling because it's not uncommon to want to write dates in source code and treat them as constants. On top of that, these routines are limited to cases where there is no or very little code duplication and the operation is itself not too complicated.

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

No branches or pull requests

1 participant