John F said:
There is a difference between
(date1+date2)/2 (adds dates and divides by two)
and
date1+(date2-date1)/2 (proportionally adds the difference between two
dates to another date)
The former is meaningless (in a mathematical sense), the latter is
perfectly legal.
[...]
The former includes a subexpression that yields a result that's not
meaningful, but the expression has a whole is meaningful.
Dates, temperatures, and pointers are all similar in the sense that
each can be thought of as a pair: base+offset, where the base is
respectively an arbitrary epoch, an arbitrary zero temperature, or a
zero address (or the base address of a containing object). In each
case, the "base" is some fixed point, and the "offset" is a scalar
quantity. Offsets by themselves can be added and subtracted freely;
the base is meaningful only if you have exactly zero or one of it.
(With no base, you have an interval or distance; with a base, you have
a position.)
(Assume Celsius or Fahrenheit temperatures; the zero base of Kelvin
scale is uniquely meaningful, so it's not restricted to this model.)
Subtracting two dates
date1 - date2
is equivalent to:
(base+offset1) - (base+offset2)
which reduces to:
offset1 - offset2
which is meaningful; it's an interval, measurable in seconds, with no
defined base.
Adding two dates:
date1 + date2
is equivalent to:
(base+offset1) + (base+offset2)
which reduces to:
2*base + offset1 - offset2
which is not directly meaningful because of the 2*base term.
However, if it's used as an intermediate expression, as in:
(date1 + date2) / 2
we have
((base+offset1) + (base+offset2)) / 2
or
(2*base + offset1 - offset2) / 2
or
base + (offset1 - offset2)/2
a meaningful expression that denotes the midpoint between the two
dates.
Ideally, we'd like to make expressions with meaningful results legal,
and expressions without meaningful results illegal. Theoretically, we
could do this by allowing meaningless intermediate results, as long as
the result of the full expression is meaningful.
There are (at least) two problems with this approach. First, it makes
the language rules more complex, which affects both compiler writers
(who can deal with it) and users (who likely can't). Try explaining
to a newbie that (date1 + date2), or (pointer1 + pointer2), is usually
illegal, except that it's allowed as a subexpression if and only if
the expression as a whole obeys certain constraints. Second, it makes
it difficult to define the circumstances in which overflow can occur.
Pointer arithmetic in C is defined only within a single object (or
just past its end); allowing pointer+pointer gives you intermediate
results that not only don't have an obvious meaning, but may not be
representable, depending on where in the address space the object
happens to be allocated.
Ignoring the overflow problem, if you're using raw numbers to
represent dates, something like (date1+date2)/2 is ok, as long as you
have the discipline to avoid writing a full expression that's not
meaningful:
x = date1 + date2; /* meaningless, but the compiler won't complain */
If you're using a hypothetical language that does this kind of smart
type checking, allowing date1+date2 as a subexpression but not as a
full expression, you can add dates to your heart's content and depend
on the implementation to detect any type matching errors. It would be
interesting to design this kind of thing, either as a language feature
(off-topic here), or as a library with run-time checking (doable in
standard C, with functions rather than overloaded operators). Again,
overflow is a concern unless you can either use extended precision for
intermediate results, or rely on the implementation to rearrange the
expressions for you.
Finally, if you're using standard C and operating on pointers, you'll
just have to rearrange the expression yourself. If you need to know
the address halfway between two pointers, you can't write:
mid = (ptr1 + ptr2) / 2;
You'll just have to bite the bullet and write:
mid = ptr1 + (ptr2 - ptr1) / 2;