Boost logo

Boost :

Subject: Re: [boost] [gsoc 2013] draft proposal for chrono::date
From: Anurag Kalia (anurag.kalia_at_[hidden])
Date: 2013-04-30 04:15:45


Hi Vicente,

Before I start, I want to ask what I should submit as a proposal to Google?
i know I am to implement date class. But the problem arises that the design
and implementation are still taking time to set in.
How can I tell them details that most probably would change in one way or
another? What should I mention in the proposal beyond that I want to
implement date class.

Moreover, what am I expected to do? Should I make all the implementations of
major representations and then test them in the course of making the date
library? I think I should (and probably I would) but I am just asking about
the expectations.

And so on to the actual discussion...

I have just read the representation part. IIUC you choose a compact
representation of a YMD. It has the same liabilities than the YMD
representation (day arithmetic) and adds in addition some drawbacks as you
need to calculate the year, month and day from this representation.

Yeah it does, now that I ponder more over it. My representation (let us call
it serial YMD) has advantage in incrementing and decrementing of months and
years. Currently, its day arithmetic is inefficient but I am sure it can be
made better and mostly on the lines of YMD date only so not much difference
there either way.

Again comparison is a toss-up. Best case of serial YMD takes two comparisons
but for the majority it suffices. YMD takes only one in best cases and
restricts itself to three comparisons at most. I think, simple YMD has
advantage here.

And I/O in YMD can't be bested by any other representation in my opinion. I
thought serial YMD is absorbing advantages of both representations but it
seems to be the opposite.

I don't think that having a single representation would solve the design of
a Date library. I think that each representation could be more efficient for
day arithmetic while been less efficient for month/year arithmetic and
vice-versa. So several representation must be provided. The problem is how
to make all of them more efficient while preserving the integrity.

I was thinking of wrapping the storage fields of date into a class, e.g. ymd
class, serial_raw class, serial_leap class, ymd_cache class etc. All of them
surface the basic functions in the same way like setter and getter functions
[year(), month(), etc], comparison, copy operations etc.

Then the general date<rep> template is able to interact with any other
date<rep2>. For example, an operation of date<ymd> - date<serial> should be
possible through the general operator- function in date template only,
returning a duration in days.

I intend to code a working prototype to show it to you, but I am still in
the middle of it though and should be demonstrable by the next day.

The problem is how to make all of them more efficient while preserving the
integrity.

I don't understand what is being conveyed here. Can I ask you to explain it
better for me please? :)

date construction

I don't like the functional construction.

date d1_2 = date(1, 2, 2011, DMY);

What do you think of the ways I included on my prototype?

      /**
       * @Effect Constructs a @c ymd_date using the @c year, @c month, @c
day stored in the arguments as follows:
       * If the value stored in @c d is outside the range of valid dates for
this month @c m and year @c y,
       * throws an exception of type @c bad_date.
       * Else constructs a @c ymd_date for which <c>get_year() == y &&
get_month() == m && get_day() == d</c>.
       * @Throws @c bad_date if the specified @c ymd_date is invalid.
       */

I can see use of all constructors except the day_of_year constructor. Since
we are making it a p. gregorian calendar, such interface shouldn't be made
public. It should rather be used in dayofyear_claendar where concept of
months doesn't exist, shouldn't it? And I like the way you have designed the
corresponding unchecked functions. As for implementation, one only needs
combined representation month_day and the data if the year is leap or not.

//rough idea:

month_day = (month-1)*31 + (day-1)

We check this value against the seven (six, if leap) days as mentioned in my
serial YMD implementation.
Actually, this approach can be used for any representation because of its
compactness.

Having opaque types for year, month and day you can add as many permutations
as you desire.

The following would not work
//operational
date d3_1 = weekday(wd)[_1st] / may / 2011;
//functional
date d3_2 = date( wd[_1st], may, 2011, DMY);

The problem is that wd[_1st] is not really the same as a day.

Yeah, I thought about that and decided to add a WMY constant. But it would
have just added mental overload of users. It is there just to tell the
compiler about the order of arguments to both compiler and a person who
reads the code. Seeing ymd added to the definition automatically tells what
the date constructor intends to do. weekday() is anyways of a different type
than day() so we can just overload the functions. I genuinely am curious why
adding that fourth parameter might be a bad design.

About the _1st, 2nd, ... , _31th, last constantand you symmetry problem,
what about having the nth to access the one before the last

nth(-1)

or just last_1st last_2nd, ...

Again, this adds extra syntax when the current one can do it all the same.
e.g. a second-to-last date can be constructed by the current syntax itself:

date d = last / jan / 2001 - days(1);

which is also perfectly readable. Shouldn't we avoid to add needless
constants?

I don't see nothing yet about validation of dates. IMO the usual constructor
must validate the date and one less fiendly could be provided when the date
must not be validated. I included a constructor for unchecked dates in my
prototype. What do you think?

      ymd_date(chrono::year y, chrono::month m, chrono::day d);
      /**
       * @Effect Constructs a @c ymd_date constructor from @c year, @c
month, @c day stored in the arguments as follows:
       * Constructs a ymd_date so that <c>get_year() == y && get_month() = m
&& get_day() == d</c>.
       */
      ymd_date(year::rep y, month::rep m, day::rep d, no_check_t)
BOOST_NOEXCEPT;

As I have said, I like this representation. Average user gets the full
error-checking without any syntactic burden. The person in need of more of
power however gets the uglier representation because it would be much less
required.

Year/Month/Day/WeekDay arithmetic

As your representation is equivalent to the YMD representation all the
algorithm in HH implementation are valid, so there is no need to extend on
this.

I/O again I don't see nothing about input.

I am not sure about this. I thought date construction is only way one can
make dates. Is it possible to change the values of an existing dates? if we
want to change the whole date, we can just use constructors and make them
assign the temporaries to the given date object.

e.g.
date d = date(1, 12, 2001);
d = date(1, 12, 2001);

If one wants to modify individual objects, the function modify may look
like:

date modify_year(int yr)
{
    int diff_y = yr - year();
    *this += years(diff_y);
    return *this;
}

Relations with chrono::system_clock

I would say just that conversion between date and
chrono::time_point<chrono::system_clock, chrono::days> can be done in both
direction.

If we want to convert into both directions, non-member functions can be
employed:

date to_date(time_point<system_clock, days>);
//and
time_point<system_clock, days> to_time_point(date);

Moreover, I realized I should start putting my date classes into appropriate
namespaces, eg. chrono::days.

BTW a century is not a multiple of days :(

Oh yeah. I didn't realize it wasn't possible generally; my implementation
has equal sized years after all. What a difference a single day makes!

I don't see the utility of days_since_epoch function we have already
time_since_epoch and if the the clock duration is days the time_since_epoch
would return in days.

Hmm. I changed the name or no particular reason thus, apart from "looking
good". Scratch that name.

Calendars

Using a common templated date class is not a good idea as the calendars
would provide different functions. Thin of chrono::date as the proleptic
Gregorian Calendar.
I suggest the namespace as done on the julian.hpp example.

 namespace julian
 {
 }

If some calendar have things in common you could move them to a specific
namespace and import them to the specific calendar namespace. This will
allow you to be as specific as you need to manage with the date conversions
between different calendars

 namespace solar
 {
   class month;
 }

 namespace julian
 {
   using solar::month;
   ...
 }

I see the solution now. But the conversions between the classes become
difficult. We have to make conversion functions for every two calendars
pair-wise. They might have much code duplicated inside but yet any change in
a class means changing these conversion functions too.

A template date <calendar, rep> would be easy to generalize. We are making
each class in each namespace; in templates, we have to specialize template
for each different calendar type. Code-duplication is mostly the same with
an extra advantage of having a generalized calendar_cast being possible.

Glad to see you start to understand the problems that must be solved.

The more I know, the more I know what I don't now. Thanks for the
appreciation though! :)

Regards,
Anurag Kalia

(Was sent again as wrong message; extremely sorry for repeated mistakes. But
I use nabble now though; I learnt it has features to reply too!)

--
View this message in context: http://boost.2283326.n4.nabble.com/gsoc-2013-draft-proposal-for-chrono-date-tp4646142p4646345.html
Sent from the Boost - Dev mailing list archive at Nabble.com.

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk