Yes. A Fluent styled expression like the following would (today) have these performance characteristics:
let calendar = Calendar.current.timeZone(timeZone).locale(locale)
|-- cache hit --|--- wasted copy --|---- copy ---|
This has the same performance characteristics as setting the properties one by one has today. To go with the Fluent inspired initialiser expressions, the first question we need to answer is: do we want to avoid the extra internal allocations? If we do not, then adding these Fluent inspired initialisers is straightforward and we turn to matters of the idiomatic, weighting the risk a new property will be added, and this becoming a potential precedent for other instances of ABI stability initialiser gymnastics.
If we want to avoid the extra allocations, then the internals of Calendar would need to change. There look to be two options for that. First, we can wait for isKnownUniquelyReferenced to work with existentials and update accordingly. Second, Calendar would need to become a value type more purely, so time zone, locale, etc properties could be added to a struct.
The second option is very involved. One way this could be done is by removing the _CalendarProtocol conformance from _GregorianCalendar, making _GregorianCalendar a value rather than a reference type, placing the properties there, and modifying Calendar to store either a Gregorian or calendar reference type. Then, getting and setting properties becomes a case of switching on the calendar's storage and accessing the property as appropriate. For example:
public var timeZone: TimeZone {
get {
switch storage {
case .gregorian(let g): return g.timeZone // reads from struct
case .other(let c): return c.timeZone // reads from reference type
}
}
set {
switch storage {
case .gregorian(var g):
guard newValue != g.timeZone else { return }
g.timeZone = newValue
storage = .gregorian(g) // simply sets a struct's property
// before, heap allocation as below
case .other(let c):
guard newValue != c.timeZone else { return }
storage = .other(c.copy(changingLocale: nil, // heap allocation
changingTimeZone: newValue,
changingFirstWeekday: nil,
changingMinimumDaysInFirstWeek: nil))
}
}
}
The details for this option could vary but I think the substance would remain. A few things to note about that substance, though. First, we can't avoid making a copy from the reference type calendars. I do not know enough about how swift-foundation is used or its obligations to say how big of a deal that is. Second, the Calendar struct gets heavier to copy around the stack and I'm not sure what subtle implication that'll have on pre-existing, high performance, memory sensitive code. Third, this option makes Gregorian calendars cheap to create, simplifying the internal caching story. Finally, another advantage is that Gregorian calendars can be used on platforms where existentials are unavailable.
I hope this detail helps the community decide if the proposal has value in itself that is not short-sighted. The proposal agrees that some sort of fluent configuration (or calendars) approach is most flexible, but suggests the need for that flexibility is unlikely. In addition to that, it seems the technical complexity of creating such an affordance (in this case) is also quite large. So I think the proposed initialiser is not unreasonably short-sighted. But I hope others can help me see where I could be wrong.