EiffelUnits is a library of units of measurement for theEiffel language. It enables you to attach units to the quantities you use in your programs. EiffelUnits includes a collection of common units along with conversion, formatting and consistency checking utilities. EiffelUnits is extensible and can be adapted to userdefined unit systems outside the SI (e.g. currencies, color values, ...). I only compiled it with ISE Eiffel 5.1  if you've tried it with other compilers, please tell me.
Contents: Scope ¤ Usage ¤ Problems ¤ Glossary ¤ References
Units of measurement are an indispensable tool in many branches of science. Our ancestor's invention of pure numbers was certainly a big step in human history. The abstraction of sets out of incommensurable goods (17 geese and 4 bottles of wine make 21 ... guess what? ... objects , of course) is often useful . But we all know that abstract classes are not enough. At times, it's recommendable to categorize values into meaningful dimensions, such that we can better track and understand what we are calculating.
Our knowledge of natural laws stems partly from a powerful technique called
Dimensional Analysis. Basically, dimensioned quantities are
nothing more than values attributed with a dimension. By noting these
dimensions explicitly, we can check whether our equations and calculations
are meaningful. All natural laws discovered so far are dimensionally
consistent, which leads us to the presumption, that there really is
such a thing as a `dimension' in nature. We can employ the dimensions
of the quantities we use as another means of ensuring correctness in our
programs because dimensionally inconsistent calculations are definitely
wrong (and thus raise an exception when incommensurable units are used).
Dimensioned quantities are a tool which enables you to write systems
that are better contracted in contrast to systems just using plain values.
Dimension  Unit 

SI base units: 

Length (L)  m (meter) 
Mass (M)  kg (kilogram) 
Time (T) 
s (second) 
Electric Current (I)  A (Ampère) 
Thermodynamic Temperature (Theta)  K (Kelvin) 
Amount of Substance (N) 
mol (mole) 
Luminous Intensity (J) 
cd (candela) 
SI supplementary units: 

Plane Angle (alpha)  rad (radian) 
Solid Angle (Omega) 
sr (steradian) 
The SI is an internationally agreed system of coherent units. It declares
7 base dimensions and exactly one unit per base dimension as a
base unit, the core reference of scale in that dimension. No other
(obsolete) unit should be used where SI units exist. A prominent example
is meter , which is the SI base unit of base dimension length
(L). Inch , mile, etc. are deprecated nonSI units.
Base dimensions are orthogonal, in the sense that no base dimension can be
expressed as a multiplicative combination of other base dimensions. Units
can be prefixed by a set of standard multipliers (e.g. centi for10^{2}
or mega for 10^{6}).
Derived units are constructed as combinations of base units. Force for example has a derived dimension (M * L * T^{2}) whose unit kg * m * s^{2} may also be written as N (Newton) .
There are two additional supplementary dimensions in the SI: the dimensions of plane and solid angles. The commitee seems not to have agreed on the nature of angular units. Even though there's little reason not to get angular units in the circle of base units, they are not "official" units. The mere fact that angular dimensions are often omitted is no justification for dropping them altogether. It is highly questionable whether we should really "merge" (meaning "confuse") the two fairly different notions of angle (a dimension with base unit rad) and dimensionless ratio ( angle / angle_of_full_revolution or length_of_circle_arc / circle_radius ). Therefore, EiffelUnits treats angular units like normal base units.
Cluster "examples" shows common usage patterns of EiffelUnits. Cluster
"test" contains some test classes.
Clients use the units and dimensions supplied with EiffelUnits. If your
application stays within the SI unit system, it's likely that all the units
you need are provided ready to use. Cluster unit.units holds classes
with base dimensions and common units in these dimensions or powers thereof
(e.g.m (meter) and l (liter) in class LENGTH, or s
(second) and Hz (Hertz) in class TIME). Class COMPLEX_DERIVED
provides some derived units with special names like N (Newton).
Class STANDARD_UNITS is a convenience class which includes all
predefined units. The easiest way for clients to get access to EiffelUnits
is by inheriting from STANDARD_UNITS. Another possibility (which doesn't
clutter the namespace of your classes) is to define an attribute of type STANDARD_UNITS
and access the units via a qualified call. Note that all classes defining
units and dimensions are expanded. This allows clients to access their
oncefunctions via an attribute without the need to create an object.


The primary notion for calculations with units is class QUANTITY.
Enities representing quantities are declared using type QUANTITY:
altitude: QUANTITY 
A QUANTITY object contains a DOUBLE value and a dimensionality.
Quantities with equal dimensionality are said to be commensurate.
Only commensurate quantities can be added, subtracted and compared to
each other. These commensurateness conditions can be stated in contracts as
shown here:

QUANTITY is an expanded class whose entities can hold
any unit or quantity. Yes, that's right: units are not special objects. They
are just quantities which happen to carry some dimension. You usually don't
have to "create" a unit for your quantity from scratch. Instead, you use once
functions from classes in cluster unit.units and employ them as factors
in multiplications and divisions with other quantity objects. Class QUANTITY_CONVERSION(which
is an ancestor of STANDARD_UNITS, but can also be used directly) provides
feature
quantity (value: DOUBLE): QUANTITY
to create dimensionless
quantities:
feature 
Temperatures in units other than Kelvin require special treatment. Instructions
are given in class THERMODYNAMIC_TEMPERATURE.
Commensurability between quantities is defined as equality of their dimensions.
Therefore, every QUANTITY has a DIMENSION attached, which is
accessible through feature dimension. Class STANDARD_DIMENSIONS
holds a set of commonly used dimensions, including the SI base dimensions.
An instance of class STANDARD_DIMENSIONS is available via feature
dim from class QUANTITY_CONVERSION, which you will most likely
inherit if you intend to use EiffelUnits.
(This example is taken from [1].) Atwood's Machine is a simple mechanical
device which consists of two unequal masses suspended by a string from a massless,
frictionless pulley. The upward acceleration a of mass m1is
given by
a = (m2  m1) / (m2 + m1)
and the tension t in the string is given by
t = 2 * g * m1 * m2 / (m1 + m2)
where g is the magnitude of the acceleration due to gravity. These simple formulas are incorporated into the following class for Atwood's machine:
class 
If you need a derived dimension which is not defined in class STANDARD_DIMENSIONS,
you can easily create it by multiplying and dividing base dimensions or existing
derived dimensions. Remember that derived dimensions do not have to be "created"
prior usage. They are generated onthefly as you execute calculations with
existing units.
Sometimes, you need a new dimension for your special field of application. In this case, you simply create a new DIMENSION object, which becomes a new base dimension (orthogonal to all previous dimensions):
class MY_CLASS inherit 
See class LENGTH_ASTRONOMY in cluster root_cluster.examples to see how you could provide additional units or constants.
This example shows how to extend EiffelUnits. New base dimensions Gasoline and Distance are created to aid in consistency checks. New units l_gasoline and m_distance are defined on top of the new dimensions.
expanded class

Units are not statically checked. Unfortunately it was not possible
to implement unit checking statically (at compile time). In complex
unit expressions, we have to deal with a great many unforeseeable
compound units. It is not feasible to manually provide classes and
operations for all possible combinations of units. Furthermore, that
approach would not be extensible.
In Eiffel, types are based either directly on classes
or on generic derivations of generic classes. Since types are not
computable on demand at compile time, I don't see a possibility to
implement static unit checking. Please inform me if you disagree and
have a solution. But remember: we don't want preprocessors or compiler
hacks. Just a clean Eiffel library.
The increased safety gained with unit checking is currently traded in for
a runtime overhead over unchecked programs.
Persistence of quantities is not supported. Base dimensions are
currently identified in once functions by a monotonous increasing
counter. Since the execution sequence of once functions is not neccessarily
the same in different sessions, dimensions are not guaranteed to
be assigned the same identifiers between runs. Therefore, quantity
objects can not be stored and retrieved safely between different executions
of a program by means of STORABLE.
A possible solution: identify a base dimension by its
symbol (e.g. "L" for length), stored in some global place. But that
would not statically ensure uniqueness.
EiffelUnits is based on ISE EiffelBase. I apologize for any inconveniences in terms of portability.
All values are DOUBLE. EiffelBase has weak support for generic
usage of numeric data types. INTEGER and DOUBLE both inherit independently
from NUMERIC and from COMPARABLE. Hence there's no common ancestor that clients
can use if they don't care about the exact data type (be that INTEGER, DOUBLE,
RATIONAL, BIG_INTEGER, etc.). The following class declaration is not legal
in Eiffel: class QUANTITY [G > {NUMERIC, COMPARABLE}] inherit ...
.
Conversion of DOUBLE value to QUANTITY. At the time of writing,
there's no automatic object conversion in Eiffel. Therefore, you have
to use feature quantity (v: DOUBLE): QUANTITY
from classQUANTITY_CONVERSION
to make the transition from (manifest) numbers to quantities. The reverse
way is feature in (unit: QUANTITY): DOUBLE
from class QUANTITY
.
Known Bugs. There are no known bugs at this time. If you find one, please crunch it and send it to me. Thank you.
[1] John J. Barton and Lee R. Nackman: "Scientific and engineering C++: an introduction with advanced techniques and examples". Reading, Massachusetts, AddisonWesley, 1994.
Further information on units of measurement and standards can befound here: