Boost logo

Boost :

Subject: Re: [boost] [chrono/date] date conversion and arithmetic with unvalidated dates
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2013-05-06 18:54:14


Le 06/05/13 22:57, Anurag Kalia a écrit :
> Vicente Botet wrote
>> Le 06/05/13 15:22, Howard Hinnant a écrit :
>>> On May 6, 2013, at 6:30 AM, "Vicente J. Botet Escriba" <
>> vicente.botet@
>> > wrote:
>>>> Hi,
>>>>
>>>> Note that N3344 suggest only day arithmetic for a day representation
>>>> (which is always valid) and suggest only only a date representation.
>>>>
>>>> Could we apply arithmetic operations on a unvalidated date (without
>>>> striving on UB)?
>>>> e.g. day arithmetic on a ymd_date
>>>>
>>>> ymd_date d1(year(2013), may, day(66));
>>>> ymd_date d2 = d1 + day(1);
>>>>
>>>> If defined, which must be the value of d2?
>>>>
>>>> Could we convert a date representation to another one if the source date
>>>> is unvalidated (without striving on UB)? e.g. ymd_date -> days_date
>>>>
>>>> ymd_date d1(year(2013), may, day(66));
>>>> days_date d2 = d1;
>>>>
>>>> If defined, which must be the value of d2?
>>> My understanding is that all of these operations (if unchecked at
>>> ymd_date construction time) are simply undefined behavior. This is what
>>> N3344 seems to be asking for.
>> N3344 doesn't suggest month and year arithmetic at all. They suggest to
>> let these features for a higher layer.
> I thought it does. It even includes a benchmark for increasing in terms of
> months.
I has a bechmarc about month arithmetic, bu the chapter 8
Recommendations exclude it and Appendix A shows an stereotype of the
recommendation without any mention to month arithmetic.
>
>
>> Should the following pass.
>>
>> ymd_date dt(year(2012),feb,day(29));
>> try {
>> dt+=years(1);
>> BOOST_TEST(false);
>> } catch (...) {}
>>
>> Or should dt contain an invalid date? I would expect that an exception
>> is thrown.
>>
>> In the same way we are proposing constructors and factories that allows
>> the user to check/uncheck the validity of the entered date, arithmetic
>> operators can be considered also as date factories
>>
>> I'd propose that arithmetic operators using operators validates the
>> result. For those that don't want to pay for validity check we can add
>> additional functions that don't check the validity
>>
>> date& date::inc(years);
>> date& date::pre_inc();
>> date& date::post_inc();
>> date& date::dec(years);
>> date& date::pre_dec();
>> date& date::post_dec(years);
>> date sum(date, years);
>> date diff(date, years);
>>
>> Or shouldn't we have two different classes, validated and unvalidated
>> dates, as Rob has suggested?
>> More I analyze the subject more I believe the separation is unavoidable.
>>
>> validated_date dt(year(2012),feb,day(29));
>> try {
>> dt+=years(1);
>> assert(false);
>> } catch (...) {}
>>
>> unvalidated_date dt(year(2012),feb,day(29));
>> try {
>> dt+=years(1);
>> // the result of dt is 2013/feb/29 which is unchecked and invalid
>> } catch (...) {
>> assert(false);
>> }
>>
>> The user can move from one date type to the other
>>
>> unvalidated_date dt(year(2012),feb,day(29));
>> try {
>> dt=validate(dt) + years(1);
>> } catch (...) {
>> assert(false);
>> }
>>
>> Best,
>> Vicente
> I am afraid I don't like this separation of dates. The current model as it
> stands simply says that the dates constructed with "raw" constructor are
> undefined. This doesn't mean that they are discarded and can't be used: one
> natural interpretation is that the dates created are assumed to be valid.
> The implementation essentially has faith in the programmer for feeding it
> the correct value.
Agreed. N3344 propose just a unchecked serial date without not too much
features that corresponds to what I named unvalidated_date.
The question is how we can extend the design to cover better with
unchecked and checked dates and how they can interact.
Whether we have one class or two is IMO an open point, from all the
discussion we have had.

>
> Also, dates constructed with validation check are of course valid. Combining
> the two, we have always valid dates when created. Thus, operations define
> their behaviour on valid dates only. It doesn't mean operation is always
> defined for valid dates. As your example suggests, "2013-02-29" + 1 year =
> "2013-02-29" which doesn't exist! Thus it is possible for valid dates to
> have no defined answer for that operation. We can either throw an error, or
> extend our operation to include those dates, say "29 feb" + 1 year maps to
> "28-feb" now.
In order to do that you need some kind of validation. This is exactly my
concern.
Should the year arithmetic be as efficient as possible (just increate
the year) and let the user to ensure the require clauses of the function)?
I would say yes, and this should be the behavior for unchecked dates.
Or should the operation check if the resulting date is a valid one a
throw otherwise?
I would say yes, and this should be the behavior for checked dates.

Having a single class don't allows us to provide both behaviors and so
we need to choose one, or I have showed we need two function flavors,
which start to make the interface quite complex.

Once we have defined both behaviors and assign them to a specific class
the user can move from checked to unchecked and vice versa depending on
what she wants to do and using always the same syntax.

> The same can be said in the cases of underflow or overflow.
> The path we choose for those dates can be argued and debated, but what we
> are not arguing is the validity of the input dates.
>
> But as you rightly ponder over is how to validate an unvalidated date. We
> can always create a date from the previous date using functions that
> validate it, say make_date(). To ease it, we can create function:
>
> make_date(date unvalidated);
>
> make_date() as before uses validation while construction of dates.
Yes, but the C++type system is not helping us to define the correct
behavior.

> The
> question though remains whether we can ever check a date for validation. As
> I said before, it is impossible for serial-based implementation.
Except if you ensure that because the type valid_date has only checked
and valid dates :)

> So, I am in
> favour scrapping any such effort and dumping any interaction with an
> unvalidated date in the undefined behaviour.
Well this is your right.
> It indicates to user to proceed
> with caution. If he/she does, well good luck! They can always build
> validation in their own system as they see fit.
>
As for example?
How the user would be able to have a different behavior if we only
provide one?

Please could tell me which behavior would you want for year arithmetic?
Would you need to provide two flavors, one unchecked and one checked, or
not?

In order to compare the different approaches and take decisions we need
to explore them.
H.H design was based on valid dates. N3344 is based on unchecked dates.
I'm just supporting the Rob idea that maybe we need both with a close
interaction if we want a clear design and easy to use/learn interface.

Best,
Vicente


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