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