[chrono/date] class names
Hi, I would like to fix the names of date classes for the different representations. I'm not saying that all the representations need to be provided for a first release. Here it is my proposal. The following are unchecked and non contextual dates classes * calendar_date: field based representation of year + month + day. * serial_date: days based representation * ordinal_date: field based representation of year + day_of_year * week_date: field based representation of year + week + weekday Checked dates classes names just add a checked_ prefix to the corresponding unchecked date classes. * checked_calendar_date: field based representation of year + month + day. * checked_serial_date: days based representation * checked_ordinal_date: field based representation of year + day_of_year * checked_week_date: field based representation of year + week + weekday We can also have an alias date template <typename Tag = serial, validity=validity::unchecked> class date; so that date<calendar> ~ calendar_date date<serial> ~ serial_date date<> ~ serial_date ... I'm, open of course, to other defaults for these parameters, if the idea of an alias is accepted. For the time been a single contextual date class should be enough, as all the contextual information is relative to the year/month/day representation. * contextual_date: field based representation of year + month + day + context-meta-data Comments, critics and suggestions are welcome. Best, Vicente
On May 11, 2013, at 12:31 PM, "Vicente J. Botet Escriba"
Hi,
I would like to fix the names of date classes for the different representations. I'm not saying that all the representations need to be provided for a first release. Here it is my proposal.
The following are unchecked and non contextual dates classes
* calendar_date: field based representation of year + month + day. * serial_date: days based representation * ordinal_date: field based representation of year + day_of_year * week_date: field based representation of year + week + weekday
Checked dates classes names just add a checked_ prefix to the corresponding unchecked date classes.
* checked_calendar_date: field based representation of year + month + day. * checked_serial_date: days based representation * checked_ordinal_date: field based representation of year + day_of_year * checked_week_date: field based representation of year + week + weekday
We can also have an alias date template <typename Tag = serial, validity=validity::unchecked> class date;
so that
date<calendar> ~ calendar_date date<serial> ~ serial_date date<> ~ serial_date ...
I'm, open of course, to other defaults for these parameters, if the idea of an alias is accepted.
For the time been a single contextual date class should be enough, as all the contextual information is relative to the year/month/day representation. * contextual_date: field based representation of year + month + day + context-meta-data
Comments, critics and suggestions are welcome.
Two questions: 1. Why are the checked-names longer/more-complex than the unchecked names? I would've thought we wanted the opposite. 2. What is the difference between the checked serial_date and the unchecked serial_date? Just range checking? Do we really want to range check a serial_date? That will make day increment/decrement a lot more expensive percentage wise. Howard
Le 11/05/13 19:07, Howard Hinnant a écrit :
On May 11, 2013, at 12:31 PM, "Vicente J. Botet Escriba"
wrote: Hi,
I would like to fix the names of date classes for the different representations. I'm not saying that all the representations need to be provided for a first release. Here it is my proposal.
The following are unchecked and non contextual dates classes
* calendar_date: field based representation of year + month + day. * serial_date: days based representation * ordinal_date: field based representation of year + day_of_year * week_date: field based representation of year + week + weekday
Checked dates classes names just add a checked_ prefix to the corresponding unchecked date classes.
* checked_calendar_date: field based representation of year + month + day. * checked_serial_date: days based representation * checked_ordinal_date: field based representation of year + day_of_year * checked_week_date: field based representation of year + week + weekday
We can also have an alias date template <typename Tag = serial, validity=validity::unchecked> class date;
so that
date<calendar> ~ calendar_date date<serial> ~ serial_date date<> ~ serial_date ...
I'm, open of course, to other defaults for these parameters, if the idea of an alias is accepted.
For the time been a single contextual date class should be enough, as all the contextual information is relative to the year/month/day representation. * contextual_date: field based representation of year + month + day + context-meta-data
Comments, critics and suggestions are welcome. Two questions:
1. Why are the checked-names longer/more-complex than the unchecked names? I would've thought we wanted the opposite. Yes we wanted it, I forgot it for an instant. I'm open to change to calendar_date, unchecked_calendar_date.
2. What is the difference between the checked serial_date and the unchecked serial_date? Just range checking? Do we really want to range check a serial_date? That will make day increment/decrement a lot more expensive percentage wise.
A checked serial date is serial date that checks the validity at construction time, either from days or from an unchecked calendar_date. So the check could be on calendar dates which is more expensive. Are we in line here? Best, Vicente
On May 11, 2013, at 2:05 PM, "Vicente J. Botet Escriba"
A checked serial date is serial date that checks the validity at construction time, either from days or from an unchecked calendar_date. So the check could be on calendar dates which is more expensive.
I understand what the check would look like from an unchecked calendar date. But what would you check when constructing a checked serial date from an unchecked days? Howard
Le 11/05/13 20:10, Howard Hinnant a écrit :
On May 11, 2013, at 2:05 PM, "Vicente J. Botet Escriba"
wrote: A checked serial date is serial date that checks the validity at construction time, either from days or from an unchecked calendar_date. So the check could be on calendar dates which is more expensive. I understand what the check would look like from an unchecked calendar date. But what would you check when constructing a checked serial date from an unchecked days?
Well, nothing if we admit that the range would be large enough to don't need validation. But checked::serial_date dt = may/11/year(2013); would be the syntax to build a checked serial date converted from a unchecked calendar date, and the validation would be done on the conversion. What do you think to using namespaces instead of prefixes? This will allow to have checked and unchecked unit specifiers as well. using chrono::checked; serial_date dt = may/11/year(2013); using chrono::unchecked; serial_date dt = may/11/year(2013); Just an idea. Best, Vicente
On May 11, 2013, at 7:13 PM, "Vicente J. Botet Escriba"
What do you think to using namespaces instead of prefixes? This will allow to have checked and unchecked unit specifiers as well.
using chrono::checked; serial_date dt = may/11/year(2013);
using chrono::unchecked; serial_date dt = may/11/year(2013);
I like that. Both sets have full names that indicated whether they are checked or not, can be simplified via using dirs/decls, and can be tuned to exactly what's required in each case. The only drawback, if you can call it that, is that code can appear ambiguous when using dirs/decls, or typedefs, are in force. That is, two functions can appear identical despite one using checked, and the other using unchecked types. ___ Rob (Sent from my portable computation engine)
On May 11, 2013, at 7:13 PM, Vicente J. Botet Escriba
What do you think to using namespaces instead of prefixes? This will allow to have checked and unchecked unit specifiers as well.
using chrono::checked; serial_date dt = may/11/year(2013);
using chrono::unchecked; serial_date dt = may/11/year(2013);
This is an interesting idea. However I'm having serious doubts that we want duplicate checked and unchecked API's. My 2011 chrono paper clearly got checked API's wrong, at least in the implementation. There was way too much redundant checking going on. There was not enough attention paid to the issue of reducing redundant validation. N3344 rightly pointed out the performance issues with my work. That being said, I now think it is quite possible that N3344 came to a few incorrect conclusions. I think we need to aggressively investigate the possibility of just having: checked field types unchecked serial types If we give up checking on range, the unchecked and checked serial types are the exact same thing. This is what chrono::duration and chrono::time_point do. With constexpr as a tool in the toolbox, and with careful thought to avoid redundant validation, checked field types seem very affordable performance wise. And the simplicity gained by not having checked and unchecked field types that are identical in API and nearly identical in performance is extremely compelling. More work needs to be done to ensure that this is indeed a viable approach. However the payoff is huge, and thus worth investigating. N3344 benchmarks: 3.3.1 Creators:
This benchmark creates date objects in a loop, repeatedly creating three fixed date values: 2000/1/1, 2000/12/31, and 2009/5/1.
The objective of this benchmark is to measure the performance of the value constructor of each date implementation.
With the use of constexpr, the validation checking for this benchmark is completely done at compile time. I admit that the benchmark needs to be improved so that it would actually measure the intended cost of conversion from run-time field information to a serial date. But my point is that this effort was not done in N3344, quite likely due to lack of constexpr-enabled compilers. 3.3.2 Accessors
This benchmark repeatedly extracts the year, month, and day from a constant date object having the value 2001/1/1, by invoking the year, month, and day accessors.
Again, this benchmark is all compile-time validation and computation. 3.3.3 Increase Day
This benchmark repeatedly advances a date object by one day, starting from date 1/1/1 and incre- menting 3652061 times.
For a serial date type, such as chrono::time_point with a period of days, this is the exact same expense as integral increment. 3.3.4 Increase Month
This benchmark repeatedly advances a date object by one month, starting from date 1/1/1 up to the year 9000.
This still needs work, however I have confidence that all validation can be removed from a checked field type for this benchmark. The initial date is constexpr'd valid, and adding n months to this date is compile-time-provable valid. 3.3.5 Array Sorting No validation issues. 3.3.6 Modified Following This is the most interesting benchmark. This is where we should really be performance testing checked vs unchecked types. I strongly suspect that with checked field types and unchecked serial types, this benchmark will not motivate the need for unchecked field types nor checked serial types. But this is work in progress. 3.3.7 Packed Calendar Needs more investigation with respect to performance. I strongly suspect that with checked field types and unchecked serial types, this benchmark will not motivate the need for unchecked field types nor checked serial types. But this is work in progress. --------- One of the conclusions that I feel N3344 got very right, but with the wrong syntax is this member function of date: void get_yearmonthday(int *year, int *month, int *day) const; N3344 is biased towards "date" being a serial date type. And the above suggested member is much better expressed as a conversion from the serial date type to the field date types. Bottom line: N3344 has some very valid criticisms. But we should not limit ourselves to addressing those criticisms in exactly the way N3344 suggests. There are other (and I think better) possibilities. And I really dislike the checked/unchecked interfaces when the performance difference between the two is only a few percent (more work needed to absolutely nail down that this is in fact the case). Howard
On May 12, 2013, at 9:33 PM, Howard Hinnant
On May 11, 2013, at 7:13 PM, Vicente J. Botet Escriba
wrote: What do you think to using namespaces instead of prefixes? This will allow to have checked and unchecked unit specifiers as well.
using chrono::checked; serial_date dt = may/11/year(2013);
using chrono::unchecked; serial_date dt = may/11/year(2013);
This is an interesting idea. However I'm having serious doubts that we want duplicate checked and unchecked API's.
[snip]
Bottom line: N3344 has some very valid criticisms. But we should not limit ourselves to addressing those criticisms in exactly the way N3344 suggests. There are other (and I think better) possibilities. And I really dislike the checked/unchecked interfaces when the performance difference between the two is only a few percent (more work needed to absolutely nail down that this is in fact the case).
I like the simplicity of this tack. Note that the standard date types need not be the fastest possible, provided that user-defined types can interoperate well enough. The standard should be about generally useful types that are safe to use right, even at the cost of some performance. (When the two coincide, all the better.) ___ Rob (Sent from my portable computation engine)
Le 13/05/13 03:33, Howard Hinnant a écrit :
On May 11, 2013, at 7:13 PM, Vicente J. Botet Escriba
wrote: What do you think to using namespaces instead of prefixes? This will allow to have checked and unchecked unit specifiers as well.
using chrono::checked; serial_date dt = may/11/year(2013);
using chrono::unchecked; serial_date dt = may/11/year(2013); This is an interesting idea. However I'm having serious doubts that we want duplicate checked and unchecked API's. I have also doubts. I see one advantage: in case the validation checks are not supportable by the user he can move easily to unchecked date interface.
My 2011 chrono paper clearly got checked API's wrong, at least in the implementation. There was way too much redundant checking going on. There was not enough attention paid to the issue of reducing redundant validation.
N3344 rightly pointed out the performance issues with my work.
That being said, I now think it is quite possible that N3344 came to a few incorrect conclusions. I think we need to aggressively investigate the possibility of just having:
checked field types unchecked serial types N3344 signal already that there were already redundant validation. The no_check parameter I and you introduced was there to avoid this redundancy. If we give up checking on range, the unchecked and checked serial types are the exact same thing. This is what chrono::duration and chrono::time_point do. Agreed for serial dates. I have some concerns. Does it means that the range of dates doesn't depend on the range on year? Or that the range on year must be large enough to represent the same date? How to ensure that both would be able to represent the same dates?
With constexpr as a tool in the toolbox, and with careful thought to avoid redundant validation, checked field types seem very affordable performance wise. And the simplicity gained by not having checked and unchecked field types that are identical in API and nearly identical in performance is extremely compelling. More work needs to be done to ensure that this is indeed a viable approach. However the payoff is huge, and thus worth investigating.
N3344 benchmarks:
3.3.1 Creators:
This benchmark creates date objects in a loop, repeatedly creating three fixed date values: 2000/1/1, 2000/12/31, and 2009/5/1.
The objective of this benchmark is to measure the performance of the value constructor of each date implementation. With the use of constexpr, the validation checking for this benchmark is completely done at compile time. I admit that the benchmark needs to be improved so that it would actually measure the intended cost of conversion from run-time field information to a serial date. But my point is that this effort was not done in N3344, quite likely due to lack of constexpr-enabled compilers. I agree. constexpr allows to validate the fields at compile time. What we have observed is that forced inline is a must for run-rime field validation. What I mean is that without constexpr and forced inline we can get already almost the same results. 3.3.2 Accessors
This benchmark repeatedly extracts the year, month, and day from a constant date object having the value 2001/1/1, by invoking the year, month, and day accessors. Again, this benchmark is all compile-time validation and computation. Evidently the benchmark need to be completed with run-time dates.
3.3.3 Increase Day
This benchmark repeatedly advances a date object by one day, starting from date 1/1/1 and incre- menting 3652061 times. For a serial date type, such as chrono::time_point with a period of days, this is the exact same expense as integral increment. Agreed.
3.3.4 Increase Month
This benchmark repeatedly advances a date object by one month, starting from date 1/1/1 up to the year 9000. This still needs work, however I have confidence that all validation can be removed from a checked field type for this benchmark. The initial date is constexpr'd valid, and adding n months to this date is compile-time-provable valid. I don't understand what you mean.
3.3.5 Array Sorting
No validation issues.
3.3.6 Modified Following
This is the most interesting benchmark. This is where we should really be performance testing checked vs unchecked types. I strongly suspect that with checked field types and unchecked serial types, this benchmark will not motivate the need for unchecked field types nor checked serial types. But this is work in progress.
3.3.7 Packed Calendar
Needs more investigation with respect to performance. I strongly suspect that with checked field types and unchecked serial types, this benchmark will not motivate the need for unchecked field types nor checked serial types. But this is work in progress.
---------
One of the conclusions that I feel N3344 got very right, but with the wrong syntax is this member function of date:
void get_yearmonthday(int *year, int *month, int *day) const;
N3344 is biased towards "date" being a serial date type. And the above suggested member is much better expressed as a conversion from the serial date type to the field date types. I suspect that N3344 didn't wanted to propose two date to the C++ standard, so the interface was there to allow the conversion efficiently. I hope that we all admit now (at least on this ML) that having two date classes is better than having only one.
Bottom line: N3344 has some very valid criticisms. But we should not limit ourselves to addressing those criticisms in exactly the way N3344 suggests. There are other (and I think better) possibilities. And I really dislike the checked/unchecked interfaces when the performance difference between the two is only a few percent (more work needed to absolutely nail down that this is in fact the case).
This is what we are doing, we are exploring the possibilities, isn't it? In addition, we want the checked interface to be not more difficult to use than the unchecked one (if at the end needed). Using the namespace would allow to move the whole checked interface to std::chrono and let the unchecked on a specific std::chrono::unchecked. But If IIUC, before proposing both interfaces we need first to probe that no validation check provides enough gain, or the opposite. Best, Vicente
participants (3)
-
Howard Hinnant
-
Rob Stewart
-
Vicente J. Botet Escriba