Skip to content

size-suggestion: Should custom calendars eagerly calculate all fields at construction time? #2852

@justingrant

Description

@justingrant

Presently, Temporal getters for calendar fields like era, year, monthCode, day, etc. will call into a custom calendar each time the getter is executed. This is inefficient.

An alternative approach is to avoid calling into Calendar during the getter and instead only call the Calendar in the constructor, using a single Calendar.prototype.calculate() function. This function would return an ordinary object with calculated values for getters. In addition to enabling other optimizations and reducing user calls, this would remove the need for 14 functions:

  • Temporal.Calendar.prototype.dayOfWeek ( temporalDateLike )
  • Temporal.Calendar.prototype.dayOfYear ( temporalDateLike )
  • Temporal.Calendar.prototype.daysInMonth ( temporalDateLike )
  • Temporal.Calendar.prototype.daysInWeek ( temporalDateLike )
  • Temporal.Calendar.prototype.daysInYear ( temporalDateLike )
  • Temporal.Calendar.prototype.day ( temporalDateLike )
  • Temporal.Calendar.prototype.era ( temporalDateLike )
  • Temporal.Calendar.prototype.eraYear ( temporalDateLike )
  • Temporal.Calendar.prototype.inLeapYear ( temporalDateLike )
  • Temporal.Calendar.prototype.monthCode ( temporalDateLike )
  • Temporal.Calendar.prototype.monthsInYear ( temporalDateLike )
  • Temporal.Calendar.prototype.month ( temporalDateLike )
  • Temporal.Calendar.prototype.weekOfYear ( temporalDateLike )
  • Temporal.Calendar.prototype.yearOfWeek ( temporalDateLike )
  • Temporal.Calendar.prototype.year ( temporalDateLike )

This issue is adapted from suggestions made by @FrankYFTang to help reduce the size of Temporal to address concerns from implementers (especially Android and Apple Watch) that Temporal's install size and/or in-memory size is too large.

From an initial quick chat with a few of the Temporal champions, we think this is an interesting suggestion!

I've got a few question about this solution. @FrankYFTang, feel free to chime in with answers if you have them:

  • Where would the object returned by calculate be stored? In a new internal slot on Plain* types and ZDT?
  • Would that slot be empty for built-in calendars? How much would it increase RAM requirements for the vast majority of objects with built-in calendars?
  • Would this new solution support calendar-specific fields? (I'm not sure the current solution supports calendar-specific fields either, but I know that this case is something that @sffc has talked a lot about!)
  • Would Temporal shallow-clone the object returned by calculate, so we're not holding onto an object that could be mutated later?
  • Would there still be a need for getISOFields() methods with this approach?
  • Would implementations really need to store a JS object with all the fields? Or could they optimize storage to leverage the fact that most fields don't require 8-byte numbers? For example, calendars could be constrained to U8 for day, month, monthCode, etc.

To set expectations, a change of this magnitude, especially if there is consensus that this is a better way to implement custom calendars than the current design, is probably beyond what we can accommodate in Temporal V1. It's just too large and would probably push out our implementation timeline by over a year. So the best course of action, if we feel that this is the right custom-calendar solution, may be to ship Temporal V1 with built-in calendars only (see #2826) so we're not locked into a sub-optimal design, and then carefully design this new custom-calendar solution for a follow-up proposal.

This is analogous to the plan for custom time zones after #2826, which is that they'd be better implemented declaratively (ideally based on an existing standard like JSCalendar) in a follow-up proposal after Temporal V1, rather than a sub-optimal, user-code-required design in V1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    size-suggestionSuggestions to shrink size of Temporal to address implementer concerns

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions