Timothy S. Nelson wrote:
On Thu, 19 Feb 2009, Darren Duncan wrote:
You could make month/day into positive integers or "subtype of Int where 1..12" etc, though it isn't strictly necessary. Leave year as Int of course, since at least in the proleptic Gregorian etc you can have negatives or zero.

I want this role to be composable into the heavy-lifting non-core non-Gregorian modules as well as into Temporal::Interval, so I'm trying not to get too specific.

Sure, fair enough.

+role    Temporal::Subsecond {
+    has    $.nanosecond;

Two things:

1. You should just make that a Rat/Num $second or $frac_second or something. I know DateTime.pm has the precedent but counting in nanoseconds is too arbitrary, especially since newer/future machines would have a higher resolution than that. Using Rat/Num will let this be open-ended.

We also want to be able to avoid floating point rounding problems too. I called the role "Subsecond" instead of "Nanosecond" because I want to make it possible for future machines to add a $.femtosecond if needed :).

Don't get hung up on floating point. That's assuming an implementation detail which will very often not exist. Instead you should be assuming that the conceptually non-integer numeric type is exact precision like a big-rat, and if any implementations are less exact, then this can be matched or undercut by a subtype spec that requests a lower resolution such that semantics are still exact, and that when rounding inevitably occurs, it happens in a user or operator specified manner. Besides, an implementation may still choose to use an integer for implementation, but its granularity can be flexible depending on the use case. Specifying $.nanosecond is short-sighted, and expecting one may add $.femptosecond later just is unnecessarily complex.

2. Why not just make normal $.second in Time be a Rat/Num instead? Users can always subtype it with "where is_desired_precision()" or something if they want that. Separating out whole and fractional seconds has a design smell to me since they measure the same unit (unlike min/hour/day/mon/year, each of which deserve to be separate).

Hmm. Well, I'll think about it for a while, and hope that Dave Rolsky will chime in on this :).

If you want good accuracy, you at least need distinct [seconds, minutes, days, months] units because in the general case those never exactly convert between each other. You need to keep them separate because they are separate units in practice. In practice you also want [years, hours], which are [1:12 month, 1:60 minutes] for Gregorian, and maybe less specific with other calendars, because that is just so useful. This goes for Instant and appropriately applies to Duration. You *only* combine units into one number if for all possible uses of those units they convert on an exact ratio. Which is why you don't combine seconds with minutes or hours with days etc. And which is why subsecond and whole-second *can* be combined. Appropriate separation allows better accuracy in letting people express what they mean rather than shoehorning it into a less accurate space, like DateTime.pm shoehorns into Days+Seconds+Nanoseconds.

Ideally in the general case, your YMDHIS collection will also support having any or all of those attributes undefined, to signify "don't know" or "don't care for that level of precision". Subtypes can mandate that any or all of the attributes are defined, so for example a typical Date would specify YMD is defined and HIS is not, and Time would specify HIS is defined and YMD is not. If you define Date|Time as subtypes of Instant then this also generalizes a way to define interactions like adding or subtracting such, and also makes it easy for people to define other levels of precision, such as all-but-seconds-defined etc. You could also bring back DateTime as a type name, which is Instant where all 6 YMDHIS attributes are defined, for example. You get some semantic symmetry or asymmetry that way where it does some good.

-- Darren Duncan

Reply via email to