datetime review part 2 [Update 4]

Dmitry Olshansky dmitry.olsh at gmail.com
Sun Nov 14 02:31:00 PST 2010


On 14.11.2010 7:47, Jonathan M Davis wrote:
> On Thursday 11 November 2010 13:42:37 Dmitry Olshansky wrote:
>>> I'm afraid that I don't really get what you're trying to do here. A range
>>> needs to be created from an interval. It really wouldn't make sense to
>>> do it otherwise. And when you create a range, it needs a delegate which
>>> generates the time points for that range. So, you create an interval and
>>> call either fwdRange() or bwdRange() on it to give it the
>>> range-generating delegate. I happen to have provided some helper
>>> functions for generating delegates, but there's nothing to stop you from
>>> creating your own.
>> If you have provided them, then it's OK.
>> What I meant is we have retro(someRange) to go backwards where applicable.
>>    And I do believe you could return range of DateTime's  that's
>> bidirectional ?
>> Then there is no need to duplicate the std.algorithm/range
>> functionality, that's all.
> None of the ranges in std.datetime are bi-directional, so you can't use retro on
> them (or any other algorithm which requires bi-directional ranges). It's a side
> effect of them being generated as you iterate. I considered having bi-directional
> ranges, but it was just too messy. You'd have to provide two separate generative
> functions (one for each direction), and in many cases, when iterating over
> dates, you wouldn't get the same results because many date calculations aren't
> reversible (the main problem being that months and years don't have the same
> number of days).
So bi-directionality is one of places where generator-on-previous-date 
approach is failing.
I see that with current API the user need to be aware which delegate use 
when:
auto func = IRange.everyDayOfWeek!(Date, 
Direction.bwd)(DayOfWeek.friday);//note the Direction.bwd bit
auto range = interval.bwdRange(func);//also note the bwd thingy
I get it would just throw exception if  bwdRange got replaced by 
fwdRange? It's acceptable, but still not clean.
>>> Are you trying to say that the range should automatically provide _all_
>>> possible time points in an interval and then you specifically filter
>>> them? That's nowhere near as flexible, and in the case of SysTime in
>>> particular, think about how many time points that is. It has
>>> hecto-nanosecond (100 ns) precision.  That's 10 million time points a
>>> second. It could get really inefficient to try and filter all of those.
>>> Also, I'm not sure that filter would work with an infinite range (I'd
>>> have to check), which would be a huge setback. I really don't get the
>>> benefit of your suggestion, though I can undkerstand it if it's not
>>> entirely clear how ranges in std.datetime are supposed to work.
>> Not at all, you provide the precision that the user asks for. E.g. if
>> users want tot iterate by days - no problem iterate by days.
>> If by hnseconds, well he(or she) knows better ... Right?
>> The point is we don't need some predefined delegates, just the natural
>> ones e.g. by secs, hours and so on as with the roll/add methods.
> That's doable, but it seems far less flexible.
OK, got it.
Skimming again through docs I'd say we just see the API at different 
sides, i.e.
I was mostly referring to IRange block, it's slightly cumbersome.

For now, I as user see it more as interval functions:
Interval.byDur(Duration) + Interval.by!"days"(x).... 
Interval.by!"months"(x) + Interval.by"years"(x)

where only byDur, by"months" and by"years" are necessary the other are 
just a convenience.
They could be implemented as one-liners in terms of yours IRange (I 
still don't get why such a name?).
Then it would be just an implementation detail with IRange being private.

But then it would cost in some extra lines, plus as you told there 
should be fwd/back param somewhere.
Then it goes like Interval.by!("days",Direction.Back) with default being 
Fwd of course...
> For instance, how would you
> calculate each successive Easter? Or a holiday which always occurred on the Xth
> day of the week of a particular month? A number of calculations could easily be
> based on the dates that came before rather than examining each date on its own
> and determining whether it was one of the ones that you were looking to iterate
> over.
Yeah, with that simplified approach using filtering by e.g. days could 
suck in term of speed, need checking.
It's however possible, see my later point. If speed is of concern IMO I 
would just create a special
range by hand, it's a standard library right?
About speed:  because of flexibility yours bwdRange and fwdRange are 
checking on both bounds(if any)
  at each iteration, for trivial tasks that's also costs.
Maybe we need some realistic date-time benchmarks (if there is such a 
thing)?
> I mean, even iterating over each successive month with that wouldn't work
> very well. If the first date were 2010-07-31, would 2010-09-30 be one of the
> dates to iterate over? In order to know one way or the other, you'd need to have
> state (like what the last date to be iterated over was), and using a filter does
> not give you state.
Filter based on delegate  could have state, so no problem at all.
     int n = 1;//state
     auto fn = (int i){
         if(i == n){
              ++n;
             return true;
         }
         return false;
     };
     int f[] = array(filter!(fn)([1,2,3,4,5,7,8]));
     assert(f == [1,2,3,4,5]);//passes
Or better you could use function-like object or what not, that's what 
std.algorithm is good at.
> It seems to me that using a filter could work well in simple cases but that it
> falls apart in more complex ones.
As you said it's not a simple case, and how would you handle it with 
current API anyway? Custom generator-delegate for grunted.
So custom in any way (range or delegate), and not everything we generate 
needs previous timepoint.
>> Well, I'm not saying it's bad/or some such. I, first of all, told you
>> it's damn good.
>> Things could be simplified though if you relay some of burden on
>> std.algorithm/range and such.
>> That's the main point I couldn't get for the moment.
> I think that the real concern is whether the ranges in std.datetime can be used
> with all of the algorithms in std.range and std.algorithm that they're likely to
> be want to used with. As they stand, they aren't bi-directional, which could be
> a problem, but I don't see a good way to make them bi-directional, since date
> calculations aren't always reversible.
Yeah, that's a pity.
> You also can't swap them at all, but they
> have a fixed order by their very nature, so I don't see that as being a problem.
> There could be problems that I'm not seeing though.
> Regardless, I don't see std.algorithm or std.range as being much help in
> generating ranges in std.datetime. It might be nice to use retro to produce
> ranges which iterate into the past, but the lack of reversibility of date
> calculations makes it so that doesn't work. And in most cases, a delegate which
> calculates the next date in the range given the previous one is quite
> straightforward - if it isn't, it's because the calculation itself is
> complicated, and attempts at using filter and the like won't make the calculation
> any simpler.
>
Indeed, so please, at least just consider changing status of IRange from 
public API to implementation artifact.
> - Jonathan M Davis


-- 
Dmitry Olshansky



More information about the Digitalmars-d mailing list