Boost logo

Boost :

From: Bjorn.Karlsson_at_[hidden]
Date: 2003-01-17 08:38:20


> From: Thorsten Ottosen [mailto:nesotto_at_[hidden]]

> Sorry for not understanding why "exceptionally creative use
> of expression
> templates" is necessary :-) Could you
> elaborate a little on it?

I'll try. :-)

We are now talking about (if I understand you and Dave correctly) three
related problems and solutions, which poses somewhat different challenges:

0) Partially controlled conversions at compile time and runtime
This is the case that is covered by your outline, as well as numeric_cast
(at least the hopefully-soon-to-be-reviewed numeric_cast that is part of
Fernando Cacciola's Numeric Conversion Library). The cast, or the type, is
responsible for preserving ranges when converting between types. For
integral constant expressions, invalid conversions are detected at compile
time, others are caught at runtime. It's partial control, because
expressions such as Int i(1000000*100000) obviously aren't detected. [No
expression templates required.]

Example:

int i1=-42;
Int i2=-42;
unsigned char c1=boost::numeric_cast<unsigned char>(i);
UChar c2=i2;

1) Controlled numeric type promotion and conversion
This would be needed for safe(r) expressions; the rules for integral
promotions, floating point promotions, integral conversions, floating
integral conversions, and the usual arithmetic conversions, would be encoded
explicitly in types or implicitly in expressions. Unary and binary
expressions are handled to produce the correct resulting type; conversions
that would lead to loss of precision or range are invalidated, either at
compile time or runtime. It is probably a nontrivial task to find consensus
on what to allow; for example, should the special rules for unsigned
arithmetic be prohibited or not? [No expression templates required here
either, but could potentially simplify and add functionality to the
implementation.]

Example:

Int i=std::numeric_limits<int>::max();
Short s=7;
UShort us=i+s; // i+s results in a type equivalent to unsigned int, and us
is assigned "the least unsigned integer
// congruent to the source integer (modulo 2n where n is the number of bits
used to represent the unsigned type)"
// , i.e. it "wraps around". Should this be legal for this safe type?

2) Complex expression conversion and promotion control

If the aforementioned mechanisms for controlling conversions and promotions
exist, there is still the matter of more "complex" arithmetic, involving
intermediate steps. This is where the expression templates need to enter the
arena, because we can no longer simply evaluate the binary operations; we
must consider the expression as a whole. If we don't, seemingly equivalent
expressions will be treated differently (just as is the case with
built-ins):

int x=1000000;
int y=1000000;
int z=1000000;

int r=x*y/z; // Probably a negative number, implementation-defined.
safe_numeric throws an exception if all variables are safe_numeric.
r=x/z*y; // 1000000. safe_numeric doesn't throw an exception.

Of course, the example is too contrived; but when passed as arguments,
different variable values (potentially) lead to completely different results
(ehrm, they probably should in most cases, but I'm referring to those that
should yield the same result...).

When adding integral constants to the expressions, such as x*y/3+z%10,
expression templates would be used for evaluation and optimization. They'd
also be used for evaluating and organizing expressions involving more than
one operator.

So, it is for this purpose that "exceptionally creative use of expression
templates" is needed (of course, my view of exceptionally creative doesn't
necessarily correlate with that of others :-)).

I don't think all of the above was the intent of your proposal though? (And
also, there might be value in a partial solution for detecting
errors/problems/strange results at runtime) The three problems stated above
seem to have great potential for solutions through class libraries (and
unlimited precision types, where art thou?), and my point has been (and is)
that 0) is already covered by numeric_cast, and might not need another
solution; the others remain open.

Bjorn


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