Some ideas dragged out of my past rewritten/translated in a Chapel context. My memory may be failing or I could have mistranslated or even have lost my marbles.
If the programmer has not thought enough about the structure of a mixed mode
expression, the last thing a compiler should do is provide a (likely) broken
way out of their laziness.
Assumptions of mixed mode arithmetic:
- Rules/Definitions/Mandates are to be orthogonal and easy to remember
-- they should be kept to a minimum
- The compiler can question the programmer's intelligence at any time
-- with lots of warnings (but that is all)
- It is not the compiler's role to be a numerical analyst
-- there are tools to help with that, e.g. Herbie
- The compiler will have the following compiler switches:
---- width of integral type of last-resort, e.g. --itolr-width=32
---- width of floating-point type of last-resort, e.g. --ftolr-width=64
-- these can be mandated within code by a pragma(t)
-- the active type is that at the compiler command line or within user code
---- when the active type is within user code, a command line value is an error
-- if the active last-resort type != that within an include file => ERROR
There is/are the concepts of:
- explicit and implicit types
-- the width of an implicit type is NEVER known
---- this will handle larger and larger reals and integral types
- a raw expression is one which
- is made up of a mix of identifiers and literals
- has no parentheses (i.e. precedence is determined by operators only)
- a label, name and identifier are the same (in this context)
Definitions/Mandates
- a param, const or var has an explicit type
- a proc which returns a value has an explicit type
---- even if that type is given to it (implicitly) at the RETURN statement
- a literal has an implicit type
---- real(w) if it contains a binary or decimal point or exponent
---- int(w) if it contains neither binary nor decimal point nor exponent
---- w is an unknown quantity
---- a literal NEVER has an explicit type
- an anonymous param is a literal which has been coerced to an explicit type
---- e.g. 1.2345678987654321:real(32)
---- it is treated as a param (which has an explicit type)
- an explicit real(p) type dominates an explicit real(q) if p > q
- an explicit int(p) type dominates an explicit int(q) if p > q
- an explicit uint(p) type dominates an explicit uint(q) if p > q
- an explicit real(f) type dominates an explicit int(g) for any f and g
- an explicit int(f) type dominates an explicit uint(g) for any f and g
- an explicit type dominates an implicit type irrespective of bit-width
- a thing is a literal|param|const|var|proc (the last four have a label)
There is only one rule:
The type of the result of an expression of things of
different numeric types is the dominant numeric type
This has a simplification:
The type of the result of an expression of things of
the same numeric type T is the numeric type T
Note:
-- the compiler is free to complain loudly if it objects to the above
-- the compiler cannot produce code that over-rides any of the above
Note that in the event that a raw expression is assigned to a pre-typed identifier, the type of that identifier is NOT the dominant type of the expression.
In evaluating a raw expression (no parentheses), the dominant type may change left to right throughout an expression:
- an identifier is coerced to the explicit type dominant at the point
in the expression where it occurs
- literals take (or assume or are coerced to) the dominant explicit type
at the point of their appearance in the expression evaluation. It is a
compile time error if the dominant explicit type (at some point in the
expression) is integral where there appears a floating point literal,
i.e. something which has an implicit type.
Should an (un-typed/un-coerced) expression be made up of
a) integral literals only, it is evaluated as if
- t.b.a.
b) floating point literals only, it is evaluated as if
- t.b.a.
c) a mix of floating point and integral literals, it is evaluated as if
- t.b.a.
t.b.a. = o.t.i. (open to interpretation) = o.f.d. (open for discussion)
There is a mandate that in the extreme says that a real(16) dominates an int(128). Anybody who exploits that, or appears to do so, is not very smart. In this event, the compiler should be complaining bitterly. Then again, anybody using a real(16) will by definition be paying a lot of attention to accuracy so it is impossible that such a problem will arise in practice. If any confusion exists, then attention is drawn to the second sentence of this paragraph.
My 2c.