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

Ergonomic replacements for panicking APIs. #1491

Closed
turalcar opened this issue Mar 6, 2024 · 15 comments
Closed

Ergonomic replacements for panicking APIs. #1491

turalcar opened this issue Mar 6, 2024 · 15 comments

Comments

@turalcar
Copy link

turalcar commented Mar 6, 2024

When a lot of panicking APIs, such as NaiveDate::from_ymd() were deprecated I thought it to be a momentary aberration and locked the version at 0.4.22. A year has passed and proven me wrong.
I replaced .pred().pred() with - Duration::days(2) and now that's deprecated too.
In all of my code from_ymd(), from_hms() etc were only used ever with literals. I don't think that's uncommon. One could try to enforce that with a macro (e. g. date!(2024, 3, 6) similarly to how print!("Hi") only accepts string literals).
Whatever a good replacement is, it should've been implemented before the old version was deprecated.

@pitdicker
Copy link
Collaborator

pitdicker commented Mar 6, 2024

@turalcar Sorry for all the deprecations. I understand they cause churn and make chrono less nice to use!

The plan is to move chrono away from a panic-by-default design to better match current rust standards.
The intention is not to reverse the deprecations.

Maybe the macro's I proposed in #1270 can be a help to you? I certainly look forward to them a lot for the same reason.
It should not be hard to port them to your project(s).

Also most methods are now const. Maybe that allows you to move some of the fallibility to compile-time?

@Lorak-mmk
Copy link

Moving away from panicking APIs is fine, but there should be more time between introducing new APIs and deprecating old.
Current situation forces us to move to new APIs - which is fine - and significantly bump our chrono dependency minimum version and I'm reluctant to impose this on our users.

@pitdicker
Copy link
Collaborator

and significantly bump our chrono dependency minimum version and I'm reluctant to impose this on our users.

May I ask what your thoughts are WRT having a minimum chrono dependency version? Are you 'reluctant to impose this' because of the deprecation warnings? And what would you consider a reasonable time?

@Lorak-mmk
Copy link

My thinking is that some of our users may not be so fast to update their dependencies. If they stay on older chrono versions, and we require a new one, then they have to either

  1. stay on older version of our library which uses older chrono
  2. be forced to update to newer version of chrono quicker
  3. Use newer chrono versions, despite not properly migrating to it - so probably needing to disable deprecation warning in the project.

Scenario 2 is good - more apps using more recent versions of library, yay. Other scenarios not so much :<
From a purely selfish perspective I prefer major releases to deprecations - in that case we can support both versions, with support guarded by feature flags, and new releases don't break CI :D
But I understand that it's most likely a worse tradeoff for many people, so my comments should probably just be ignored.

Regarding the reasonable time - I'm not sure, I didn't think about it. I just felt that in this case it was a bit too short - deprecation of old APIs a little bit over a month after introduction of new APIs, and after 2 minor releases (from what I see: 25 January, 0.4.33 - introduction, today, 0.4.35 - deprecation).

@pitdicker
Copy link
Collaborator

Thank you for the thoughtful comment.

Let me link #1408.

@turalcar
Copy link
Author

turalcar commented Mar 6, 2024

Maybe the macro's I proposed in #1270 can be a help to you?

This looks perfect. I suppose macros for TimeDelta would also be in order.

Also most methods are now const. Maybe that allows you to move some of the fallibility to compile-time?

Any compiler worth its salt would replace the whole NaiveDate::from_ymd_opt(2024, 3, 6).unwrap().with_hms_opt(7, 0, 0).unwrap().and_utc() with a constant so I'll probably leave it as is. Besides, Option::unwrap() isn't const on stable so I'd have to reimplement that too.

@djc
Copy link
Contributor

djc commented Mar 6, 2024

My thinking is that some of our users may not be so fast to update their dependencies. If they stay on older chrono versions, and we require a new one, then they have to either

  1. stay on older version of our library which uses older chrono

  2. be forced to update to newer version of chrono quicker

  3. Use newer chrono versions, despite not properly migrating to it - so probably needing to disable deprecation warning in the project.

I don't see how this could happen. Within a semver-compatible version range, only one copy of a library can be used. So if your downstream users adopt a new version of your crate and that crate requires a newer version of chrono, downstream users will automatically also get the same newer version of chrono.

Do you have a concrete example of any issues like this that have come up?

@Pascualex
Copy link

What is the currently recommended way of initializing a const Duration? Panicking APIs have been deprecated, but unwrap isn't const yet.

@pitdicker
Copy link
Collaborator

pitdicker commented Mar 11, 2024

What is the currently recommended way of initializing a const Duration? Panicking APIs have been deprecated, but unwrap isn't const yet.

I'm also missing a const alternative to unwrap. In chrono we are internally using an expect macro: https://github.com/chronotope/chrono/blob/v0.4.35/src/lib.rs#L718. An unwrap macro can look similar.

Edit:

macro_rules! unwrap {
    ($e:expr) => {
        match $e {
            Some(v) => v,
            None => panic!(),
        }
    };
}

@archer884
Copy link

Yeah, I've never called any of these methods based on anything that WASN'T a constant value. Now I get to go in and add a lot of unwrap calls for the sake of ergonomics. Talk about annoying.

@pitdicker
Copy link
Collaborator

Published chrono 0.4.36 which undoes the deprecations on TimeDelta.

@mladedav
Copy link

@djc

My thinking is that some of our users may not be so fast to update their dependencies. If they stay on older chrono versions, and we require a new one, then they have to either

  1. stay on older version of our library which uses older chrono

  2. be forced to update to newer version of chrono quicker

  3. Use newer chrono versions, despite not properly migrating to it - so probably needing to disable deprecation warning in the project.

I don't see how this could happen. Within a semver-compatible version range, only one copy of a library can be used. So if your downstream users adopt a new version of your crate and that crate requires a newer version of chrono, downstream users will automatically also get the same newer version of chrono.

Do you have a concrete example of any issues like this that have come up?

The issue there is that the dependant crate may be using chrono at an old version and purposefully did not update because they didn't want to deal with the deprecations. But as you said if any of their other dependencies uses a newer chrono version, then they are also forced to use that version and they have to either deal with the deprecations or ignore them. Or if they still want to avoid that, they cannot update chrono itself as well as any other library which internally or even transitively uses newer versions of chrono.

@djc
Copy link
Contributor

djc commented May 21, 2024

Pinning dependency versions in (low-level) libraries is almost always a bad solution that people shouldn't do -- you didn't really answer the question for concrete examples, though?

@mladedav
Copy link

Crate alpha depends on chrono = "0.4." and its lockfile has it at 0.4.0. It also depends on beta@1.0.0 which itself also depends on chrono = 0.4.

alpha purposefully doesn't update and keeps the lockfile as is because they do not want to deal with deprecations. Now beta updates its chrono dependency to chrono = 0.4.35 which has deprecations and releases 1.1.0. Now if alpha wants to use the new features in beta@1.1.0, it will also force it to use a newer version of chrono` and they have to deal with the warnings at that time.

No library pinned a dependency version but a semver compatible update of one library caused a lot of deprecation warnings for another one.

I don't see how this could happen. Within a semver-compatible version range, only one copy of a library can be used. So if your downstream users adopt a new version of your crate and that crate requires a newer version of chrono, downstream users will automatically also get the same newer version of chrono.

That's the issue the comment was getting at exactly, the users are forced to update chrono if they use it directly and deal with the deprecations.

For the record, I'm not saying there shouldn't be deprecations or that every deprecation should be handled with a major version update, I'm just trying to explain the scenario since you said you don't see how this could happen.

@djc
Copy link
Contributor

djc commented May 23, 2024

I'm going to close this issue. I think the changes have been a net good for panic safety which is important for robustness even though I don't dispute there has been a cost in ergonomics -- but, I think prioritizing robustness over (some amount of) ergonomics is generally the accepted approach in the Rust ecosystem. That said, if people want to argue for concrete improvements that don't have some of the downsides of the older API I'd happy to see issues/PRs about that.

(For example, go upvote or give feedback on #1270.)

@djc djc closed this as not planned Won't fix, can't repro, duplicate, stale May 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants