Please vote on std.datetime

Jonathan M Davis jmdavisProg at gmx.com
Fri Dec 10 12:00:39 PST 2010


On Friday 10 December 2010 08:15:09 Dmitry Olshansky wrote:
> On 10.12.2010 3:26, Andrei Alexandrescu wrote:
> > Jonathan M. Davis has diligently worked on his std.datetime proposal,
> > and it has been through a few review cycles in this newsgroup.
> > 
> > It's time to vote. Please vote for or against inclusion of datetime
> > into Phobos, along with your reasons.
> > 
> > 
> > Thank you,
> > 
> > Andrei
> 
> First, let me state my concerns.
> I'm very disappointed with how the range interface introduced in
> std.datetime, let me pick an example from ddoc:
> auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27));
> auto func = IRange.everyDayOfWeek!(Date, >>>Direction.bwd
> <<<)(DayOfWeek.fri);
> auto range = interval.>>>bwdRange<<<(func);
> 
> *(emphasis mine)
> Note the verbosity caused by conflating two concepts  - the flexible way
> of getting a range of time points by consequently applying the delegate
> to a given start time point, and traversing an interval of time in a
> certain direction.
> 
> Time ago I pointlessly argued with Jonathon to just drop the flexible
> way of iterating intervals, replacing it by simplistic "stride by a
> adding given duration to the begining of interval until you hit end". In
> the end I observed it was very limited view as it can't effectively
> solve the "give me the next five Easters" problem, and  hastily retreated
> :)
> 
> So I to come up with an alternative, see the attached sketch of it. The
> main idea - provide and infinite range based on aforementioned flexible
> principle, simple example is (for ints):
> auto r = powersOf((int x){ return x*2; }, 1); // 2,4,8,...
> given the fact that delegate already contains information about
> direction of traversing (if any), the user the free to use it as is:
> take(r,10); // 2,4... 1024
> 
> in case with dates that is:
> auto inf = powersOf(IRange.everyDayOfWeek!(Date)(DayOfWeek.monday),
> Date(2010,Month.dec,11));
> take(inf,5);//next 5 mondays, forward is default in everyDayOfWeek
> 
> Then comes the second concept of confining ranges in intervals, here it
> goes:
> auto interval =
> Interval!Date(Date(2010,Month.dec,1),Date(2010,Month.dec,20));
> auto conf = confine(inf,interval);//Mondays in the interval iterated
> from the beginning
> 
> And the simplistic approach of fixed duration striding:
> fwdRange(interval, dur!"days"(2)); //yup, traverse by two days
> same goes for bwdRange
> 
> To summarize it:
> 1) remove fwdRange, bwdRange from each of Interval types (all it does is
> to require to retype them all over again) and make them  free functions
> with above simple functionality
> 2)  drop IRange, and let those delegates not handled by simple case to
> just float around (they are very unlikely to conflict with anything IMHO)
> 3) speaking  of which - separate the notion of applying delegate (that
> could even be generalized in std.algorithm someday) to obtain range, and
> confinement of produced range to interval.
> 
> A fitting finale would be to say... that _yes_, I would like to see this
> library in Phobos!
> Though with just proposed change if gets any traction...
> Overall it's a fantastic work, thanks Jonathon.

Overall, I don't really see the benefit of your proposal. The main advantage of 
fwdRange and bwdRange in the interval types instead of just a single function is 
that they allow you to verify that you're iterating in the correct direction. 
Otherwise, you risk an infinite loop. If we were willing to forgoe that, then you 
could make it so that you only had one function, but I think that that would be 
a definite loss.

It _is_ annoying to have to give Direction.fwd or Direction.bwd to the functions 
in IRange when you're feeding it to fwdRange or bwdRange since it does seem 
redundant, but those functions need to know what direction you want them to 
iterate in, and both fwdRange and bwdRange are designed for general delegates - 
not necessarily just those generated by IRange - so they assume the direction. 
But since the functions in IRange default to Direction.fwd and that's almost 
always what you'd want, I don't think that it's ultimately that big an issue.

Conceptually, I think that it makes perfect sense that the interval would have 
the range functions on them - that's certainly what happens with containers. I 
don't see the benefit in splitting them out.

Your solution makes it so that a range is infinite separately from whether the 
interval is infinite. I don't think that that makes sense. A range is only 
infinite because it's iterating over something infinite. By making the range 
infinite separately, it's then possible to try and iterate infinitely over a non-
infinite interval, which would be a problem.

For the most part, it looks like all you've done is try to make it so that the 
ranges are unrelated to the intervals that they iterate over. That seems like a 
bad idea to me, and I fail to see the benefit. What does your solution do that 
mine can't?

My solution is completely generalized. You can use take() and all of those 
std.range and std.algorithm functions on the ranges in std.datetime. You can 
give it a delegate defined as you like as long is it takes a time point and 
returns a time point of the same type. If you got your range via fwdRange(), 
then the time point returned must be after the one given, and if you got your 
range via bwdRange(0, then the time point must be after the one given. It's 
fairly straightforward and not error-prone.

I agree that the IRange functions are a bit ugly, but they're an attempt to make 
it easier to create common delegates to pass to fwdRange() and bwdRange() rather 
than you having to create your own. You don't have to use them. They're for 
convenience. And they include a function which generates a delegate which causes 
the range it iterate by a given duration every iteration: IRange.everyDuration!
().

I'm certainly open to suggestions, but I don't understand what's broken about my 
solution that yours fixes. My seems fairly straightword.

1. You have an interval - be it infinite or finite.

2. You want a range, you pass a delegate (which determines how to iterate over 
the interval) to fwdRange() if you want to iterate forwards and bwdRange() if 
you want to iterate backwards. fwdRange() and bwdRange() verify that the 
delegates that you give the return time points which are valid for iterating 
over the interval (so, not duplicating the previous time point or iterating in 
the wrong direction).

3. If you don't want to create your own delegate, then you use one of the 
functions in IRange to generate one for you.

4. Once you have your range, you can do whatever you normally do with input and 
forward ranges.

- Jonathan M Davis


More information about the Digitalmars-d mailing list