tc39 / proposal-temporal

Provides standard objects and functions for working with dates and times.
https://tc39.es/proposal-temporal/docs/
Other
3.35k stars 153 forks source link

Forward progress checks when calling user-controlled methods? #2356

Closed anba closed 2 months ago

anba commented 2 years ago

Should there be checks to ensure forward progress when calling user-controlled methods? For example when adding one week to a given date, should there be a requirement that the result date is after the initial date?

Example:

let cal = new class extends Temporal.Calendar {
  #dateAdd = 0;

  dateAdd(date, duration, options) {
    console.log(date, duration);
    this.#dateAdd += 1;

    // Loop ten times without making progress in RoundDuration, step 11.f.
    if (this.#dateAdd < 10) {
      // Go back and forth by one day.
      duration = this.#dateAdd & 1 ? "P1D" : "-P1D";
    }

    return super.dateAdd(date, duration);
  }
}("iso8601");

let relativeTo = new Temporal.PlainDate(1970, 1, 1, cal);

let duration = Temporal.Duration.from("P10D");
let result = duration.round({smallestUnit: "week", relativeTo});

console.log(result.toString());

This case often comes into play when creating tests to cover edge cases, like to ensure ℝ(Number.MAX_VALUE) + 1 - ℝ(Number.MAX_VALUE) is correctly computed as 1.

ptomato commented 2 years ago

In the past we haven't added checks like this, because it's trivial anyway to make user methods that hang. However, I do see the utility of these checks as being a guard against inadvertent bugs, rather than against malicious code.

ptomato commented 1 year ago

In the champions meeting of 2023-01-05 we decided not to add the complexity of these checks to the proposal. So we won't be making any normative changes as a result of this issue. However, @gibson042 and @sffc would like to see the calendar protocol documented in prose, editorially. We'll keep this issue open to track their proposal for where to put this documentation.

sffc commented 1 year ago

I was initially thinking that the place to put this prose would be in each prototype function, like Temporal.Calendar.prototype.dateAdd, with a spec text friendly equivalent of:

If DurationSign(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]]) > 0, then it is expected that result.compare(date) > 0

But I'm also happy with @gibson042's idea of putting all of these non-normative invariants in a single section somewhere in Section 12 Temporal.Calendar Objects.

ptomato commented 2 months ago

Without custom calendars, there is no calendar protocol to document.