Boost logo

Boost :

Subject: [boost] [chrono] Interoperability with ICL and common concepts
From: Joachim Faulhaber (afojgo_at_[hidden])
Date: 2011-03-15 12:31:14


Hi Vicente and Boost Chronoists,

thank you for implementing Boost.Chrono! It's a very fine piece of software :)

Currently I'm checking out the usage of chrono types with
icl::intervals and interval containers. Obviously, using intervals of
chrono::time_points or chrono::durations can be an important use case.
Also ICL already works well with other date and time data types from
boost data_time, so chrono's interoperability should be at least as
easy.

A problem here is, that Icl, while working instantly with built in
data types (e.g. int, short, double or even int*), for other numeric
types (e.g. boost::rational) or types "based on integral types" (e.g.
data_time::ptime) I needed to provide adapter code.

I think it'd be ideal, if boost libraries interoperated with each
other just out of the box, of course. To achive this, we have to find
a common understanding of those concepts, that make a seamless
interoperability work. I think, this is important work to be done,
because it widens the view from one's own library perspective to a
broader horizon of generic interplay.

The problem:
There is a minimal set of requirements that Icl expects for the domain
types of intervals and interval containers
(1) A zero element, more precisely an identity element w.r.t. the
type's composition operation, which usually is +. An assumption that
works well for all built in types and many STL-types is, that we get
this element by the default constructor T().
(2) A strict weak ordering <
(3) For all discrete types and for continuous numeric types: Operators
++, -- (Only pre-variants needed e.g. ++x)
  (3.1) For discrete types ++/-- increments/decrements by a *least step*
  (3.2) For continuous numeric types ++/-- increments/decrements by a
*unit step*.

Most of the functionality of Icl works if requirements (1) through (3)
are met. In addition, there are some functions that require a distance
type, but only for more specific types, namely for numeric types that
use varying interpretations of the origin (zero), like epoch based
date and time and pointer-addresses. BTW, do we already have a name
for this type of concept?

origin_based_equidistant_scalar
origin_based_equidifferential_scalar

because they are based to an arbitrary origin, but have comparable
differences or distances. Or shorter

equidistant_scalar
equidifferential_scalar

because if we emphasize, that by "comparable differences or
distances", it is implied that the origin is choosable. May favorite
is "equidistant_scalar". This concept reminds me of "Levels of
measurement"
http://en.wikipedia.org/wiki/Level_of_measurement

(4) For such equidistant scalar types D the ICL assumes, that the type
of the difference values of D is D::difference_type.

To summarize, for a domain type Dom, Icl expects
Dom(), <, ++, --
and if dom is a equidistant scalar type we expect an associated type
Dom::difference_type
to be defined.

Now boost::chrono::duration
(D1*) Has a default ctor that leaves the type undefined.
(D2) Has <, Ok.
(D3) Has ++, --, Ok.

boost::chrono::time_point
(T1) Has a default ctor that implements the semantics assumed by the ICL, Ok.
(T2) Has <, Ok.
(T3*) Does not have ++, --.

(T4*) Does not have difference_type

So I end up with 3 of my requirements not met (D1, T3, T4)

D1: Default ctor for chrono::duration leaves objects undefined.
I assume this is due to efficiency considerations, nevertheless
unfavorable from the view point of my library. For all built in types
and most of the STL there has been something like an intuitive maybe
unconscious may be conscious agreement to assign the identity element
w.r.t. the fundamental composing operation of the constructed object's
type as the semantics of the default ctor. From an algebraic, generic
and interoprability point of view (and IMHO) this is the best choice.

This choice has not been taken for chrono::durations, which is a
little inconsistent also, because interestingly for its
chrono::time_point type the semantic is just the desired one.

The possibility of default ctor customization is no remedy, because
ICL should ideally be completely "chrono agnostic" and still
interoperable. For the same reason duration::zero() is not an option.

T3: chrono::time_point does not implement ++ and --.
I assume this is because of the specific maths that is designed for
chrono::time_points (P) and durations (D) where
- : P x P -> D
+ : P x D -> P
+ : D x P -> P
but
+ : P x P -> P //verboten

But this should not be an argument against ++ and -- because the
"least steppable unit" for integral rep types as well as the "unit"
for floating point rep types, that is processed by ++ and -- is the
same for time_points and durations.

T4: Finally, difference_type as the associated type for time_point is
not defined. IMO, it should be, because from a concept point of view,
chrono::time_point falls in the same equidistant scalar concept that
other types are in (e.g. T*, random_access_iterator<T>) and those
associate a difference_type.

These are the main problems of Icl/Chrono interoperability. There are
a few minor ones as well. Let's discuss these first. I hope we can
arrive at a solution, where Icl can be chrono agnostic and vica versa
and still everything works well together. Based on that, we could fix
similar issues for other libs like data_time.

Cheers,
Joachim

-- 
Interval Container Library [Boost.Icl]
http://www.joachim-faulhaber.de

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