scanon
(Steve Canon)
1
Duration has the following static methods:
public static func seconds<T: BinaryInteger>(_ seconds: T) -> Duration
public static func seconds(_ seconds: Double) -> Duration
public static func milliseconds<T: BinaryInteger>(_ milliseconds: T) -> Duration
public static func milliseconds(_ milliseconds: Double) -> Duration
public static func microseconds<T: BinaryInteger>(_ microseconds: T) -> Duration
public static func microseconds(_ microseconds: Double) -> Duration
public static func nanoseconds<T: BinaryInteger>(_ value: T) -> Duration
For no good reason, the obvious additional method:
public static func nanoseconds(_ nanoseconds: Double) -> Duration
was omitted from the proposal and implementation. It's somewhat useful. It's relatively simple to implement inside of Duration (where we can use _Int128), but relatively hard to implement well outside of the standard library. We should add it.
An implementation is available here.
35 Likes
jrose
(Jordan Rose)
2
I assume it was omitted because it’s always going to truncate? round? the value, and Duration is documented to not have sub-nanosecond precision. But it doesn’t seem harmful to have it when someone could just as easily say Duration(milliseconds: value / 1000) as Duration(nanoseconds: UInt64(value)).
2 Likes
scanon
(Steve Canon)
3
To be clear, Duration has attosecond precision. The APIs that do stuff with durations generally do not.
6 Likes
jrose
(Jordan Rose)
4
I completely misremembered. Yeah, I can’t think of a reason either then.
xwu
(Xiaodi Wu)
5
Since we’re on the topic of omissions from these APIs, can we add the overloads that make + commutative (as Strideable already does, and thus all clock and duration types, but not instant types) as well as *?
extension InstantProtocol {
// Exists:
public static func + (_ lhs: Self, _ rhs: Duration) -> Self
// Omitted:
public static func + (_ lhs: Duration, _ rhs: Self) -> Self
}
public protocol DurationProtocol: Comparable, AdditiveArithmetic, Sendable {
// Exists:
static func * (_ lhs: Self, _ rhs: Int) -> Self
// Omitted:
static func * (_ lhs: Int, _ rhs: Self) -> Self
}
extension Duration {
// Exists:
public static func * (_ lhs: Duration, _ rhs: Double) -> Duration
public static func * (_ lhs: Duration, _ rhs: Int) -> Duration
// Omitted:
public static func * (_ lhs: Double, _ rhs: Duration) -> Duration
public static func * (_ lhs: Int, _ rhs: Duration) -> Duration
}
2 Likes
ktoso
(Konrad 'ktoso' Malawski 🐟🏴☠️)
6
Agree on the addition and that it would be good to do a holistic pass about what else is missing here and do it all together.
2 Likes
scanon
(Steve Canon)
7
Assuming these don’t hurt typechecker performance, sure.
1 Like
scanon
(Steve Canon)
8
Agreed, and I will, but we should be willing to take small proposals for obvious missing API without asking every would-be contributor to do this. The possibility of other improvements doesn’t have to hold up a small obvious change.
15 Likes
Missed opportunity to call this a nano-Pitch 
15 Likes
Karl
(👑🦆)
10
Seems reasonable. Can this also be @backDeployed?
1 Like
scanon
(Steve Canon)
12
I thought about it, but a "nanopitch" feels more like one of our "change five words in a docc comment" proposals.
4 Likes
The problem with Strideable is that it would require SignedNumeric which requires being able to multiply two durations together and get the same type back (which is kinda nonsense)
xwu
(Xiaodi Wu)
14
Sorry, I’m not proposing Strideable conformance; I’m saying that those types in the proposal which already conform to Strideable have commutative +, but other types don’t have commutative +, and we can take the opportunity to address that inconsistency here because being able to add a duration to an instant in one order but not another is not an entirely intuitive limitation (or necessary, unless it messes up overload resolution performance).
4 Likes
mgriebling
(Mike Griebling)
15
What algorithms are used by typechecker or how does one know a particular change affects its performance?
scanon
(Steve Canon)
16
We ask the CI system to measure compiler performance on a PR. This isn't perfect, but it's the best proxy we have.
Jeehut
(Cihat Gündüz)
17
I've read somewhere that there are reasons not to provide them, but from a practical point of view, I don't understand why minutes, hours, days, and weeks are missing. They have a pretty clear meaning and even if there exist calendars where their meanings might be different, with documentation their meanings can be made clear. I would optimize for the vast majority of use cases here.
I've actually defined a helper in my own library here that adds these APIs. So I thought maybe they should be considered (again) when doing a "holistic pass about what else is missing here".
days (and weeks) can have leap seconds. the duration API lets us advance instants by durations, and we probably don’t want people writing things like
let tomorrow:ContinuousClock.Instant = today.advanced(by: .days(1))
if you write
let tomorrow:ContinuousClock.Instant = today.advanced(
by: .seconds(24 * 60 * 60))
you probably still have a bug, but at least it’s less surprising if today is 4:20 PM today and tomorrow isn’t 4:20 PM tomorrow.
2 Likes
Jeehut
(Cihat Gündüz)
19
I write this kind of code all the time. But I don't see it as a problem because I don't need second-level exactness. As a leap second is introduced less than once a year, it would require 60 years to make a difference of one minute. I see the point about exactness, but again, that could be solved with documentation, a warning or something else.
Jeehut
(Cihat Gündüz)
20
For a developer who doesn't know that there's something like a leap second, it's as surprising to them as if they used today.advanced(by: .days(1)). And if a developer knows about leap seconds, documenting that Duration.days isn't leap-second aware should be good enough, I think. I would guess that such a pure "Duration" representing API doesn't know anything about any calendrical things.
Just my noob opinion though, I'm no expert in this topic.