Version 1.2 of acs/ac-00184.txt

Unformatted version of acs/ac-00184.txt version 1.2
Other versions for file acs/ac-00184.txt

!standard 4.5          10-02-09 AC95-00184/01
!class Amendment 10-02-09
!status received no action 10-02-09
!status received 09-10-27
!subject System of Units
!summary
!appendix

From: Martin Dowie
Date: Tuesday, October 27, 2009  11:58 AM

FWIW... [Editor's note: This conversation forked from one on AI05-0175-1.]

Although the pilot (or any user of an avionic system) is presented with degrees,
it's very likely that value is converted before being 'used' by the underlying
software system. I've seen them converted into a fixed-point range -1.0 ..
1.0-small; float range -180 .. 180; float range -pi .. pi; float range -1.0 ..
1.0 and probably others.

I think getting a "System of Units" addition to the language would help here
more than trying to create a super-set solution to the curiosities of deg/rad,
az/el, u/v/w or lat/long. If there were a SoU feature to the language I'm pretty
sure that building lat/long et al packages on top would be much simpler.

****************************************************************

From: Franco Gasperoni
Date: Tuesday, October 27, 2009  12:52 PM

Having a System of Units in Ada and having the type system catch unit
inconsistencies would be very helpful indeed

****************************************************************

From: Dmitry A. Kazakov
Date: Tuesday, October 27, 2009  1:28 PM

Yes, but these are different issues. A system of units as used in physics
ignores representation issues of model numbers. When you deal with
floating-point dimensioned numbers you can ignore these issues because
floating-point is "closer" to reals than the fixed-point model, it is already
inaccurate and this inaccuracy "covers" the issues which become pressing for
fixed-point. There you have to control rounding, and that will be in terms of
units. The same value in feet and in meters would be numerically different, so
the outcome of the operations will depend on the unit. Which is equivalent to
the obvious fact that the small is dimensioned. It is also so with
floating-point, but we ignore that because floating-point is already inaccurate.
(However, for example Constraint_Error in feet and Constraint_Error in meters
are semantically different, which is just ignored) Now let you divide
fixed-point feet by fixed-point hours what is the small of the result
fixed-point type?

****************************************************************                                                                                                                                                                                                
                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                
                                                                                                                                                                                                    ult fixed-point type?

From: Randy Brukardt
Date: Tuesday, October 27, 2009  1:23 PM

We spent a lot of time on various proposals for this the last time, and we were
not able to come up with anything that was both useful and worked semantically.
All we could do was allow the "deletion" of operators with abstract, so that
tools that create the appropriate set of types and operators could define only
the operators that they need.

Go read AI95-00324 (especially the !appendix) to see why this problem is so
hard. There also were several comp.lang.ada threads on this topic.

This "units checking" has been a sort of holy grail for some Ada users since the
beginning of the Ada language. But everyone seems to have a different idea of
what they mean by this - it's almost always some silver bullet that would
magically eliminate half of the work and errors in programs. Moreover, everyone
who has studied the problem seriously has come to the conclusion that a useable
solution is extremely hard -- essentially impossible within the Ada framework.
As such, it is a terrible waste of time to spend any energy on this issue.

I realize that any time some expert says something is "impossible" they are
usually wrong. I would be very happy to be proved wrong on this point. All you
have to do is propose some *new* scheme that doesn't run into the usability,
performance, implementability, compatibility, and consistency with the rest of
the language problems that every other proposal has run into.

In the absence of someone doing that, there is nothing to do here. The best way
to implement systems of units in Ada is to use a tool to define the dozens of
types and hundreds of operators needed (or do those declarations by hand: it
only needs to be done once per project). But there is so little commonality
between the needs of different projects that there doesn't seem to be anything
more that can be done.

Go ahead. Prove me wrong. Or stop whining.

P.S. Next time someone says that they want a units checking solution without any
indication of what they mean by that, I am going to scream!! You'll hear me in
Europe!!

****************************************************************

From: Edmond Schonberg
Date: Tuesday, October 27, 2009  2:06 PM

We've been discussing internally a simple scheme involving subtypes and pragmas,
that should do most of the job and be extremely lightweight.  I notice that the
beginning of AI95-0324 mentions that such was considered but discarded because
it represented too much of an implementation burden.  It's true that it's all
compiler work, but it appears to us quite doable.  Nothing will be ready to
discuss next week, but hopefully we'll have a prototype implementation in a
couple of months, that the community can experiment with. (Is this good enough
to stifle your scream, at least before Valencia :-)?

****************************************************************

From: Martin Dowie
Date: Tuesday, October 27, 2009  2:46 PM

That sounds really encouraging.

I appreciate Randy's frustration with this always coming up but to us mere
users, it's a little galling to see C++ guys getting this (via Boost) and even
Java had a language addition proposal (http://jcp.org/en/jsr/detail?id=275) and
there not be anything really on the table for Ada!

****************************************************************

From: Randy Brukardt
Date: Tuesday, October 27, 2009  3:45 PM

There are very good solutions to this problem that do not involve the language (similar to the C++ "solution" you mention above). I personally feel that the package generator tool solution provides the best possible result, as the resulting package adds no
 runtime overhead, is well-integrated with the language (because it *is* the language), doesn't have any compatibility problems, and so on. One could imagine a language-defined package to provide a solution to the problem, but it would only be useful for a
 small subset of units problems (thus the tool approach is more promising IMHO). Ada 2005 addressed the major shortcoming of the tool approach in Ada 95 by providing a way to "delete" predefined operations. The only problem with that as *the* solution is t
hat it isn't something that we can put into the Ada standard (it has nothing to do with tools), and thus it doesn't have the visibility needed. (There also is a minor issue with user-defined I/O attributes, but that hasn't g
ten much traction in general.)

From another message:

> We've been discussing internally a simple scheme involving subtypes
> and pragmas,
> that should do most of the job and be extremely lightweight.

I'm dubious that doing "most of the job" has much value. Tucker's proposal tried to do "most of the job" but turned out to do rather little of it.

I'm also against "solutions" that look bolted on -- that are not well integrated into the language. The tool solution is much better than that; the resulting package does not have integration problems.

I also strongly dislike pragmas controlling legality rules. I will strongly oppose any attempt to add such pragmas for any reason whatsoever (it's not specific to this idea).

So you've got three strikes already in my book. I realize that your description of the proposal is so sketchy that I might be reading too much into it, and a fuller proposal might be less objectionable.

> I notice that the beginning of AI95-0324 mentions that such was
> considered but discarded because it represented too much of an implementation burden.
> It's true that it's all compiler work, but it appears to us quite doable.
> Nothing will be ready to discuss next week, but hopefully we'll have a
> prototype implementation in a couple of months, that the community can
> experiment with. (Is this good enough to stifle your scream, at least before
> Valencia :-)?

No, for the reasons given above. But even if those can be mitigated, such a proposal would be too late for this round of Ada improvements; there is only a week left before the deadline for proposals. So I don't think it will help the users much (solving th
is problem in 2020 is not of much interest to the current Ada users!).

Personally, I would like to see some attempt to standardize an Ada units tool set. I'm not sure what form such standardization should take, but I think the tool ought to be widely available as a part of all Ada toolkits.

****************************************************************

From: Edmond Schonberg
Date: Tuesday, October 27, 2009  4:20 PM

here is a sketch of what we have in mind, as an internal GNAT development. It is clearly too late to include this in the forthcoming revision of the language and should be considered an invitation for comments for the development of a compiler-specific too
l, nothing more.  If it seems to meet the needs of the community we can consider it for inclusion in Ada2020 or thereabouts!

---

   A simple model for physical dimension checking in GNAT.

Periodically someone in the Ada community asks for some tool to do dimensional
checking, thinking that the strong typing of the language and the ability to
define arithmetic operators should make this easy. It turns out that a naive
approach that defines ,for example:

   function "*" (X, Y : Length) return Area;

runs rapidly into a combinatorial nightmare: there are always additional
operators to declare, expressions rapidly become ambiguous, the burden on the
programmer is high, and the attempt is eventually dropped.

AI95-0324 proposed a generic model to systematize this approach, and added a
very elegant I/O facility for dimensioned values, but was criticized (most
energetically by Christof Grein) because it did not solve the combinatorial
explosion.

We want to propose a simpler scheme, based on pragmas and subtypes, and fully
static. The following fragment gives an intuitive picture of the approach:

    package MKS_Units is
       type MKS_Value is new Long_Float;
       subtype Meter is MKS_Value;
       pragma Dimension (Meter, 1, 0, 0);

       m :  constant Meter := 1.0;
       mm : constant Meter := 0.001;

       subtype Square_Meter is MKS_Value;
       pragma Dimension (Square_Meter, 2, 0, 0);

       subtype Time is MKS_Value;
       pragma Dimension (Time, 0, 0, 1);

       sec : constant Time := 1.0;

       subtype Acceleration is MKS_Value;
       pragma Dimension (Acceleration,  1, 0, -2);
       g : constant acceleration := 9.81 * m / (sec ** 2);
    ...

A similar package would be available for CGS (and Britsh?) units.

The pragma Dimension specifies the dimensional structure of a given subtype.
The three (or four, if we use a gaussian system) exponents are rational
numbers whose numerator and denominator are literals. The elegant Rational
package developed by Christof Grein is part of the intended implementation,
but of course internally every Ada compiler also has some rational numbers
implementation, for arbitrary precision arithmetic.

The compiler knows how to handle integer and fractional powers, predefined
square root, and elementary functions. every Units package will contain an
instantiation of Ada.Generics.Elementary_Functions for the common floating-
point type.

If dimensional checking is active, the compiler does the usual arithmetic on
exponents for every arithmetic operation and assignment (including parameter
passing) and warns of a mismatch.  We do not want the implementation-defined
pragma to affect the legality of the program.

****************************************************************

From: Bob Duff
Date: Tuesday, October 27, 2009  6:17 PM

> I also strongly dislike pragmas controlling legality rules. I will
> strongly oppose any attempt to add such pragmas for any reason
> whatsoever (it's not specific to this idea).

Randy, I think maybe you've forgotten the real rule about this -- the above is half right.  ;-)

If a pragma makes an otherwise-illegal program legal, it's normally considered to be in poor taste.  The other way around is OK -- nothing wrong with a pragma that one uses to place some restriction on oneself, thus making a legal program illegal.

The most obvious example is pragma Restrictions (one of my favorite pragmas, and certainly not in poor taste).  It's purpose is of course to make some legal programs illegal.

There are many other examples.  I just did a quick read of Annex L, and it looks like 19 out of 50 language-defined pragmas have this property.

For implementation-defined pragmas, there is Impl Advice to this affect (since Ada 95).  This makes sense -- it means if you have such pragmas in your program, and want to port to another compiler that doesn't understand them, it is likely to work.  Note t
hat I insisted on the weasel-word "Normally" in that Advice.  ;-)

For the "System of units" discussion, a pragma (whether language defined or implementation defined) that makes it illegal to multiply meters*meters-->meters is in perfectly good taste.

****************************************************************

From: Randy Brukardt
Date: Tuesday, October 27, 2009  6:42 PM

> Randy, I think maybe you've forgotten the real rule about this -- the
> above is half right.  ;-)

No, after rereading Robert Dewar's rant on good taste in pragmas (it's filed in
AI05-0163-1 if anyone wants to see it), I came to realize that I just plain hate
pragmas. They're almost always a sub-par solution to a problem.

It is OK, of course, for an implementation to define pragmas (it's pretty much
all implementers have), but I dislike the language doing so.

All that said, the proposal that was actually posted seems about as good as a
pragma solution could be. But I'd actually prefer a solution with real teeth.
(BTW, I wonder what the rules in generics for these (sub)types are. Whatever
they are, they'll cause trouble, I think. If you enforce the units rules, you'll
have problems with simple things like Text_IO. If you don't enforce the rules,
you'll have an easy way to circumvent the rules - intentionally or
unintentionally. I know, I'm starting to think like Steve. ;-) But I haven't
asked yet what happens if you apply this pragma to a task with a progenitor --
I'm still learning. ;-)

****************************************************************

From: Dmitry A. Kazakov
Date: Wednesday, October 28, 2009  3:34 AM

> We want to propose a simpler scheme, based on pragmas and subtypes,
> and fully static.

In cases where units are massively deployed, like automation, they are not
always static. E.g. you should be able to write a code working with dimensioned
values, which unit constraint is unknown until run-time. Simple example is a
non-generic dimensioned I/O package.

BTW, how are you going to pass the pragma Dimension as a formal generic
parameter?

****************************************************************

From: Jean-Pierre Rosen
Date: Wednesday, October 28, 2009  5:43 AM

> here is a sketch of what we have in mind, as an internal GNAT
> development. It is clearly too late to include this in the forthcoming
> revision of the language and should be considered an invitation for
> comments for the development of a compiler-specific tool, nothing more.
>  If it seems to meet the needs of the community we can consider it for
> inclusion in Ada2020 or thereabouts!

IIRC, there was long ago a paper (by N Cohen, or was it P. Hilfinger?) about
checking dimensions *dynamically* with a discriminated type and proper
redefinition of operators (many other papers, notably by Grein/Kazakof since).
He claimed that although it was dynamic, a compiler could be smart enough to
detect violations at compile time.

It seems to me that what you are proposing with pragmas is nothing more than
what could be accomplished with the discriminated approach. So why not make a
package with the discriminated type, and let compiler magic recognize this type
and do what you propose. Compilers without special magic would still provide the
dynamic check.

A pragma Special_Scrutiny (or whatever, maybe Restriction (no_inconsistency, on
=> T) might be required to allow inhomogeneous operations to be rejected, but it
should go through Randy's taste filter.

****************************************************************

From: Franco Gasperoni
Date: Wednesday, October 28, 2009  6:30 AM

JP, do you have a pointer to that paper?

****************************************************************

From: Jean-Pierre Rosen
Date: Wednesday, October 28, 2009  7:11 AM

There is a famous paper (Grein, Kazakov, Wilson) about all issues with dimension
computing in the proceedings of AE 2003 (Toulouse), LNCS 2655. It references a
paper by Hilfinger, "An Ada package for Dimensional Analysis" in ACM
Transactions on Programming Languages and Systems, vol 10(2), April 1988.

It might be the one, although I had memories of seeing it in Ada Letters, but a
quick scan of my old collection did not find it (but I have holes in it).

Too bad Google does not (yet) index paper...

****************************************************************

From: Edmond Schonberg
Date: Wednesday, October 28, 2009  10:37 AM

> In cases where units are massively deployed, like automation, they are
> not always static. E.g. you should be able to write a code working
> with dimensioned values, which unit constraint is unknown until
> run-time.
> Simple example is a non-generic dimensioned I/O package.

The scheme I have in mind is strictly compile-time.  It will not cover all 6
points of your great survey article, but should do the important part of the
job: compile-time checks, no run-time overhead, support for derived types and
composite types of dimensioned components, and some generic programming.  An
important desideratum is simplicity :   given that this project currently has
an internal budget in the femto- euros, there is no point is planning for
peta-lines of code.

I think that the important need is to validate scientific computations, the
proper I/O issue seems less important to me (and obviously requires much more
elaborate mechanisms, as described in A95-0324).

> BTW, how are you going to pass the pragma Dimension as a formal
> generic parameter?

My inclination is to have no dimensionality checking in generic code, but rather
perform the proper checks on instances, when the actual (sub)types are known.
So there is no need to extend dimension checking to the contract model. In any
case, if I have a gaussian solver or a sorting routine, I don't see where
dimensions would come into play.

****************************************************************

From: Edmond Schonberg
Date: Wednesday, October 28, 2009  10:42 AM

>It seems to me that what you are proposing with pragmas is nothing more
>than what could be accomplished with the discriminated approach. So why
>not make a package with the discriminated type, and let compiler magic
>recognize this type and do what you propose. Compilers without special
>magic would still provide the dynamic check.

Mostly because the magic of a pragma is much cheaper than the magic of hidden
discriminants, that will represent a huge development effort, and still requires
the redefinition of operators.  There are reasons why this pioneering paper has
not seen a single solid implementation in 21 years :-)!

>A pragma Special_Scrutiny (or whatever, maybe Restriction
>(no_inconsistency, on => T) might be required to allow inhomogeneous
>operations to be rejected, but it should go through Randy's taste filter.

We already have a pragma Suppress for this very purpose, and Suppress
(Dimensionality_Checking) will probably be handy.  I think this is usable only
if it is lightweight and give few false positives, so it requires an equally
lightweight mechanism to turn it off.

****************************************************************

From: Jeffrey R. Carter
Date: Wednesday, October 28, 2009  10:44 AM

> IIRC, there was long ago a paper (by N Cohen, or was it P. Hilfinger?)
> about checking dimensions *dynamically* with a discriminated type and
> proper redefinition of operators (many other papers, notably by
> Grein/Kazakof since). He claimed that although it was dynamic, a
> compiler could be smart enough to detect violations at compile time.

I was on a project where we used such a package for development. Once we had the
units straight, for production we replaced the discriminated record type with a
straight floating-point type. This worked very well. Something that wouldn't
have required us to replace the type would have worked even better.

****************************************************************

From: Jean-Pierre Rosen
Date: Wednesday, October 28, 2009  11:26 AM

> Mostly because the magic of a pragma is much cheaper than the magic of
> hidden discriminants, that will represent a huge development effort,
> and still requires the redefinition of operators.  There are reasons
> why this pioneering paper has not seen a single solid implementation
> in 21 years :-)!

I never mentionned /hidden/ discriminants. I was really thinking of something
like:

type Unit (M,K,S,A : Integer) is
   record
      Value : Float;
   end record;

The basic information is exactly what you provide to the pragma...

****************************************************************

From: Christoph Grein
Date: Thursday, October 29, 2010  7:45 AM

> I was on a project where we used such a package for development.
> Once we had the units straight, for production we replaced the
> discriminated record type with a straight floating-point type.
> This worked very well.

This is exactly what my SI units package can do.

In case you do not have the AE 2003 paper, you can find it here:

http://www.christ-usch-grein.homepage.t-online.de/Ada/Dimension.html

****************************************************************

From: Christoph Grein
Date: Thursday, October 29, 2010  7:45 AM

Basically I am on Randy's side (i.e. I don't think that it's worth the effort to
add dimensions to Ada), but I'm very curious to see how AdaCore's (Ed's)
proposal works out.

subtype ESU is CGS_Value;  -- charge: g**(1/2) * m(3/2) / s pragma Dimension (esu, 3/2, 1/2, -1);

How do you specify which numeric pragma parameter defines which fundamental
unit? So which is which in the line above? How many of them may there be? MKS 3,
MKSA 4, Gaussian CGS 4, (full) SI 7. Is it customizable? Astrophysics might use
sun masses, parsecs, centuries as fundamental units (dunno).

Someone might even use it for currencies and define a "dimension" for each one:
Euro ?, US-$, Swiss Francs, Turkish Lira ... Are there then 20 or more numeric
parameters in pragma Dimension, as many currencies as this someone is going to
consider?

XYZ: MKS_Value := Some_Complicated_Formula;  -- which dimension does this have?

This must be dynamically typed (and then constrained to the initial dimension).

ABC: MKS_Value;  -- which dimension here? Is this illegal?

ABC might be needed for some intermediate value - who cares for its dimension.
It most probably will be an awful combination of fundamental units without a
name.

****************************************************************

From: Christoph Grein
Date: Thursday, October 29, 2010  7:54 AM

> Basically I am on Randy's side (i.e. I don't think that it's worth the
> effort to add dimensions to Ada), but I'm very curious to see how
> AdaCore's (Ed's) proposal works out.

There is an erratum to the AE 2003 paper you can also find here:
http://www.christ-usch-grein.homepage.t-online.de/Ada/Dimension.html
It states:
"There are embarrassing details of the fiasco that are not included in the
reports -- primarily management failures."

This is why I don't believe in unit checking added to Ada - the problems are
normally buried somewhere else.

****************************************************************

From: Dmitry A. Kazakov
Date: Thursday, October 29, 2010  12:33 PM

> Basically I am on Randy's side (i.e. I don't think that it's worth the
> effort to add dimensions to Ada),

I disagree. Dimensions themselves might be of little importance. The language
mechanics necessary to express constraints similar to ones dimensions impose on
the operations is of an immense importance for the whole language. I strongly
believe that we should not build dimensions into the language. Instead of that
we should extend it so that an implementation of dimensions became possible at
the library level.

> How do you specify which numeric pragma parameter defines which fundamental
> unit? So which is which in the line above? How many of them may there be? MKS
> 3, MKSA 4, Gaussian CGS 4, (full) SI 7. Is it customizable?

That is the reason why Unit should be a compound type. You could pack there as
much components you wanted. The compiler should compare Unit on equivalence =,
and calculate Unit*Unit, Unit/Unit, Unit**Power. These operations should be
abstract, provided by the programmer.

> Astrophysics might use sun masses, parsecs, centuries as fundamental units
> (dunno).

Hmm, these are still M, L, T, nothing new.

> But that Someone might even use it for currencies and define a "dimension" for
> each one: Euro ?, US-$, Swiss Francs, Turkish Lira ...

From a unit system point of view it would make no sense. The dimension is
"currency" in all cases.

> ABC might be needed for some intermediate value - who cares for its dimension.

Yes, this is a strong argument in favor of dynamic dimensions support, even if
actually all units are statically known, they aren't to the programmer.

We will always return the fundamental issue of the compiler removing memory and
time overhead imposed by static constraints. The case of units is a mere
illustration why this technique, if existed, would be so great language
improvement.

****************************************************************

From: Robert C. Leif
Date: Thursday, October 29, 2010  1:17 PM

From the time of Bill Whitaker, many of us, who are engaged in engineering
and/or science have desired a means to check units in Ada at compile time
without having any significant run-time overhead. This is effectively what we
did in the age of slide-rules. Bill Whitaker has already provided what appears
to be an adequate solution if one would permit run-time checking. I believe that
the use of a pragma is to be preferred to any increase in the complexity of the
Ada language. Could you conjure up a compile-time only check where the generated
code would omit the run-time checking? This could also be a compile time only
assertion.

****************************************************************

From: Edmond Schonberg
Date: Thursday, October 29, 2010  2:00 PM

> How do you specify which numeric pragma parameter defines which fundamental
> unit? So which is which in the line above? How many of them may there be? MKS
> 3, MKSA 4, Gaussian CGS 4, (full) SI 7. Is it customizable? Astrophysics might
> use sun masses, parsecs, centuries as fundamental units (dunno).

Most likely we want names for the pragma arguments, and those not mentioned
default to zero.

> Someone might even use it for currencies and define a "dimension" for each
> one: Euro ,, US-$, Swiss Francs, Turkish Lira ... Are there then 20 or more
> numeric parameters in pragma Dimension, as many currencies as this someone is
> going to consider?

We were discussing internally such uses (someone suggested the need for
computing dollars per furlong, which I suppose is some measure of the
productivity of race horses).  My sense is that all of this is of interest
chiefly for scientific and engineering computations, and there is no point in
extending this model farther.  For anything involving currency, I would think
that we want decimal types anyway. not floating-point ones.

> XYZ: MKS_Value := Some_Complicated_Formula;  -- which dimension does this have?

This must be dynamically typed (and then constrained to the initial dimension).

> XYZ gets its dimensions from the rhs, and indeed this becomes constrained.

> ABC: MKS_Value;  -- which dimension here? Is this illegal?

I would make this illegal.  If dimensional checking is some specialized form of
a typing discipline, there is no point in encouraging untyped constructs.

> ABC might be needed for some intermediate value - who cares for its dimension.
> It most probably will be an awful combination of fundamental units without a
> name.

Then it should be initialized. Leaving it like this is an invitation for
multiple uses of ABC with different dimensions, a sure recipe for mistakes.

In any case, my intent is obviously much more modest that your comprehensive set
of packages.  I wanted to ask you about the user feedback you have gotten for
it:  if it has been embraced by the community as the proper way to perform
dimensional analysis, there might be no point in a compiler-based tool, we
should just point anyone who brings up the topic to
   http://www.christ-usch-grein.homepage.t-online.de/Ada/Dimension.htm

(which everyone interested in the topic should read in any case)

****************************************************************

From: Jeffrey C. Carter
Date: Thursday, October 29, 2010  2:21 PM

> This is exactly what my SI units package can do.

Sounds good. The project was c. 1996 and used Ada 83.

****************************************************************

From: Bob Duff
Date: Thursday, October 29, 2010  2:44 PM

> We were discussing internally such uses (someone suggested the need
> for computing dollars per furlong, which I suppose is some measure of
> the productivity of race horses).

This web site:

http://itotd.com/articles/286/furlongs-per-fortnight/

says that the speed of light is exactly 1,802,617,500,000 furlongs per
fortnight, which fits nicely into your scheme, as I understand it.  ;-) But I
don't believe the "exact" part.

****************************************************************

From: Christoph Grein
Date: Friday, October 30, 2010  2:53 AM

> Most likely we want names for the pragma arguments, and those not
> mentioned default to zero.

But which names? It's rather arbitrary what you take as a base unit.
SI chose Ampere because current is easier measurable than charge.

British units use BTU as a fundamental unit for one of energy, power, work
(don't know which) if I'm not too mistaken where SI has a derived unit instead.
How you will deal with this?

[Need some more pragmas to first define the basic unit names that will later be
used in pragma Dimension ;-)]

What if you want two systems, e.g. {m, s} and {nautical miles, knots} in
parallel?

> ABC: MKS_Value; -- which dimension here? Is this illegal?
>
> I would make this illegal. If dimensional checking is some
> specialized form of a typing discipline, there is no point in
> encouraging untyped constructs.

Yes, necessarily, if you want checking during compile time.

> Then it should be initialized. Leaving it like this is an invitation
> for multiple uses of ABC with different dimensions, a sure recipe for
> mistakes.

This would mean we have to insert local declares everywhere we need an
intermediate value. Desirable? But inevitable.

> In any case, my intent is obviously much more modest that your
> comprehensive set of packages.  I wanted to ask you about the user
> feedback you have gotten for it:

None for the SI units package, Big Bang to Universe is used here in several
airborne systems, no feedback from others; and I don't know whether Dmitry has
some for his packages.

****************************************************************

From: Niklas Holsti
Date: Friday, October 30, 2010  3:53 AM

> What if you want two systems, e.g. {m, s} and {nautical miles, knots} in
> parallel?

I may be misunderstanding the discussion, but it seems to me that two different
issues are involved, and should be separated:

- First, checking physical dimensions. The goal is to prevent errors such as
  adding a length (meters) to an area (meters*meters). Any attempt to do so is
  an error.

- Second, checking physical units. The goal is to prevent errors such as adding
  a length in meters to a length in feet. An attempt to do so could be
  classified as an error, or could conceivably invoke an implicit rescaling of
  one or both operands (I would not want such automatic rescaling, however).

The AdaCore proposal (which I rather like) so far seems to address only the
first issue, dimensions, and not the second issue, units, which Christoph is
asking about. The AdaCore proposal could be extended to handle some of the units
issue by adding a pragma parameter that names the system of units (eg. "MKS")
and requiring at compile-time that all operands in an expression must use the
same system of units. There would be a small set of predefined systems of units.
Conversions between units (eg. feet to meters) would be unchecked.

Another way would be to extend the dimension values in the pragma to include the
name or abbreviation of the unit, for example

    pragma Dimension (esu, (3/2,"m"), (1/2, "g"), (-1, "s"));

The compiler could then check that all operands use the same unit names.

I wonder if it would be useful to formulate this dimensions/units question using
the concepts of aspect-oriented programming? In this view, the AdaCore pragma
specifies an aspect of a subtype, and the compiler treats the assignments and
application of arithmetic operations on these subtypes as cutpoints, where
aspect-specific rules are applied (at compile-time) to check that the incoming
aspect values (operand dimension and perhaps units) are compatible, and to
derive outgoing aspect values (result dimensions and perhaps units).

****************************************************************

From: Franco Gasperoni
Date: Friday, October 30, 2010  6:30 AM

> Another way would be to extend the dimension values in the pragma to
> include the name or abbreviation of the unit, for example
>
>     pragma Dimension (esu, (3/2,"m"), (1/2, "g"), (-1, "s"));
>
> The compiler could then check that all operands use the same unit names.

That is interesting. One possibility - rather than using strings - would be to
use type names directly. Let me put on the table an extension of Ed's proposal
to all units and unit systems

    package Predefined_Units is

       --  The "mother" of all units

       type Some_Unit is new Long_Float;
       pragma Universal_Unit (Some_Unit);

       --  Some "core" units

       subtype Meters  is Some_Unit;
       subtype Seconds is Some_Unit;

       --  Some "multi-dimensional" units

       subtype Meter_2 is Some_Unit;
       pragma Dimension (Meter_2, Meter, 2);

       subtype Velocity is Some_Unit;
       pragma Dimension (Velocity, Meters, 1, Seconds, -1);

       subtype Acceleration is Some_Unit;
       pragma Dimension (Acceleration, Velocity, 1, Seconds, -1);

       --  Some "scaled" units

       subtype Millimiters is Some_Unit;
       mm_2_m : constant := 0.001;
       pragma Conversion (mm_2_m, Millimeters, Meters);

       subtype Feet is Some_Unit;
       ft_2_m : constant := 0.3048;
       pragma Conversion (ft_2_m, Feet, Meters);

       --  Some constants

       m   : constant Meters       := 1.0;
       mm  : constant Millimiters  := 1.0;
       ft  : constant Feet         := 1.0;
       sec : constant Second       := 1.0;
       g   : constant Acceleration := 9.81 * m / (sec ** 2);

and now let's use this package:

       ...
       L1 : Feet        := ...;
       L2 : Millimiters := ...;
       L3 : Meters      := ....;
       T  : Seconds     := ...;

       V  : Velocity := (L1 * ft_2_m + L2 * mm_2_m + L3) / T;

If for some reason we mistakenly wrote

       V  : Velocity := (L1 + L3) / T;
or
       V  : Velocity := L1 / T;

we would get a compile-time warning (or error if we asked the compiler to treat
this type of warning as an error).

Ed's proposal like this extended version of Ed's proposal requires a restricted
symbolic manipulation engine which should be within the realm of compiler
implementation.

****************************************************************

From: John Barnes
Date: Friday, October 30, 2010  6:09 AM

I wouldn't bother about ridiculous units such as nautical miles and knots.
How about the Flemish Ell and English scruple?

I was brought up on cgs (centimetre, gram, second).  It is curious that the gram
is quite small and that the metre is quite large otherwise the obvious system
would be mgs.

What do you mean Big Bang to Universe?

****************************************************************

From: Edmond Schonberg
Date: Friday, October 30, 2010  9:17 AM

This topic seems to have awakened the language designer / tool
designer in the community!   I think the problems to be addressed, in
order of decreasing importance, are the following:

a) Provide a mechanism for defining a set of units

b) Provide a tool for dimensional checking within a given system of units.

c) Provide a mechanism to check mixed use of several systems of units

d) Provide a user-friendly I/O system for display dimensioned values with their
   names.


For a), we need a set of names and a numeric type.

       type MKS_Names is (Meter, Kilogram, Second, ....Candela);
       type MKS_Value is new Long_Float;
       pragma Dimension_Names (MKS_Value, MKS_Names);

and then specific quantities are defined by subtypes, for example::

        subtype Length is MKS_Value;
        pragma Dimensions (Length, meter => 1);  --  named association available, default values

        m : constant Length := 1.0;

etc.  All of this appears within package MKS_Types. The same scheme can be used
to define other systems of units:

       type Electrotechnics_Names is (Volt, Ampere, Second);
       type Electrotechnics_Value is new Long_Float;
       etc.

      type Old_Saxon_Names is (Furlong, Dram, Fortnight);
      type Old_Saxon_Value is new Float;
      ...

b) Is provided within the compiler in the obvious way.

Requirement c) seems to me less important, and here Ada provides already the
first step:  diferent sets of units have different numeric types. It is
reasonable to require users to describe their formulae in one consistent system.
If an expression mixes meters and furlongs, it will simply get a type error.
However, there is an occasional need to mix units, and then the user will have
to supply explicit conversions.  Ideally, those conversions would provide the
proper scaling factors, but the simple scheme proposed here cannot achieve this
for free. Without more machinery it's not possible to indicate that meters and
furlongs are in fact dimensionally compatible.  This does not seem critical (if
the existence of the MKS package encourages the world to rally once and for all
around the decimal system, the much the better!). Judicious use of names can
help, but is not fool-proof

        seconds_per_fortnight: constant := 14 * 24 * 3600.0

d) will be helped by the use of dimension names, but nothing as ambitious as
   Christoph's SI package I/O facilities is being proposed for now.

****************************************************************

From: Jeffrey R. Carter
Date: Friday, October 30, 2010  1:02 PM

> I was brought up on cgs (centimetre, gram, second).  It is curious
> that the gram is quite small and that the metre is quite large
> otherwise the obvious system would be mgs.

Yes. It seems the definition of the gram is "wrong". If the unit of length is
the meter, then the unit of mass should be the mass of a cubic meter of water
[what we currently call a ton(ne)].

It's also curious that we use the same time unit in both systems. If the idea is
that "large" units have to be used together, shouldn't the time unit be larger
for the system with the larger length and mass units?

It's also curious that the length and time units are arbitrary, while the mass
unit is derived from the length unit and from the nature of the universe. A
second is a non-decimal fraction of the mean solar day, and the meter a
non-decimal fraction of the circumference of the Earth, but the gram is the mass
of a cubic centimeter of water.

It always seemed to me that having selected a time unit, which is arbitrary, one
should generate the length unit from a decimal multiple of the distance light
travels in that time, and the mass unit can then be generated from that length
unit.

But this seems to be a tad OT.

****************************************************************

From: Dmitry A. Kazakov
Date: Saturday, October 31, 2010  3:37 AM

> Yes. It seems the definition of the gram is "wrong". If the unit of
> length is the meter, then the unit of mass should be the mass of a
> cubic meter of water [what we currently call a ton(ne)].

That depends on the pressure and temperature. And why water and not air, gold,
or for that matter the ARM (Springer Edition)? (:-))

BTW, the unit of mass is kg, not g. SI is good balanced.

Yet, for example, atmospheric pressure goes into hPa (100 Pa), capacitance is
too big (Farad), cars are too speedy for m/s etc.

> It's also curious that we use the same time unit in both systems. If
> the idea is that "large" units have to be used together, shouldn't the
> time unit be larger for the system with the larger length and mass units?
>
> It's also curious that the length and time units are arbitrary, while
> the mass unit is derived from the length unit and from the nature of
> the universe. A second is a non-decimal fraction of the mean solar
> day, and the meter a non-decimal fraction of the circumference of the
> Earth, but the gram is the mass of a cubic centimeter of water.

Meter was introduced by the French Academy of Sciences from the Earth's meridian
length in XVIII century.

Second was a 60th part of hour, which was again derived from an Earth's
constant. (The factor 60 is because of Babylonians.)

> It always seemed to me that having selected a time unit, which is
> arbitrary, one should generate the length unit from a decimal multiple
> of the distance light travels in that time, and the mass unit can then be generated from that length unit.

The first motivation behind unit choices has always been an ability to create
master copies. So the first units used human body (e.g. foot). Later one
switched to the Earth measures, because it has less variety than humans.
Presently units are based on kernel physics.

****************************************************************

From: Stephen Leake
Date: Saturday, October 31, 2010  10:40 AM

> This topic seems to have awakened the language designer / tool
> designer in the community!   I think the problems to be addressed, in
> order of decreasing importance, are the following:
>
> a) Provide a mechanism for defining a set of units
>
> b) Provide a tool for dimensional checking within a given system of
> units.
>
> c) Provide a mechanism to check mixed use of several systems of units
>
> d) Provide a user-friendly I/O system for display dimensioned values
> with their names.

This is a good list.

It doesn't have to be in the compiler; an ASIS-based tool, or a SPARK feature,
would be more appropriate, I think. SPARK would be able to extend the units
analysis into generics and shared subprograms whose units must be dynamic.

****************************************************************

From: Robert Leif
Date: Saturday, October 31, 2010  12:47 AM

I have worked through units in the XML Schema Definition Language (XSDL).
Since XSDL data-type definitions can and should be made as a one-to-one
correspondence to those in an Ada specification, my XSDL results are relevant to
Ada.

I separate the prefixes from the units. The prefixes and units can each have
multiple formats. There are multiple ways to abbreviate them. I have attached a
zip file that contains the relevant schemas. I believe that it would be useful
to have Ada output XML that conforms to parts of these schemas. I have included
one schema about.xsd that serves as a template for the header sections of all of
my CytometryML schemas. The information in the UCUM schema is based on others'
work (1). The CytometryML collection of schemas is located at
http://www.newportinstruments.com/cytometryml/cytometryml.htm.

I suspect that the take-home lesson from my work is that a knowledge of Ada
really helps when one works with other languages. In fact if Ada companies want
to work in multiple languages, there may be significant profit in XML products.
GNAT tools are far more mature than I presently use for XML schema.
Unfortunately neither of the two products that I use, XMLSpy nor Stylus Studio,
provide a make file. XSDL does not use any library technology to keep track of
the files. The result is cumbersome. In this regard Ada is far superior.  I have
observed some practices that I do not believe would have occurred had the
programmers known Ada and software engineering. These include the use of case to
distinguish data-types and two letter names for a significant number of
data-types. The naming of schemas (packages) after the code-names of the
committees that were responsible for their creation.

1) The Unified Code for Units of Measure, Gunther Schadow Regenstrief Institute
for Health Care and Indiana University School of Medicine Clement J. McDonald,
Regenstrief Institute for Health Care and Indiana University School of Medicine
Version: 1.6 (contains important corrections)
Revision: $Revision: 1.2 $ Copyright C 1998-2005, Regenstrief Institute for
Health Care.
All rights reserved.
http://aurora.regenstrief.org/UCUM/ucum.html#section-introduction

****************************************************************

From: Christoph Grein
Date: Wednesday, November 18, 2010  7:24 AM

I like this proposal. [He's referencing the proposal of October 30th - Editor.]
I presume that the compiler will have to create some
hidden discriminants (like my SI units package) for unit checking during compile
time, but discriminants will not exist in the executable code.

However I would not recommend using unit symbol names for constants like
   m : constant Length := 1.0;
because they are case sensitive and Ada is not. Apex is well known for
automatically choosing capitalized style resulting in changing mS (Millisiemens)
in Ms (Megaseconds).

I would prefer

   subtype Meter is MKS_Value;
   pragma Dimension (Meter, ?meter => 1);  --  named association

but we would then have to resolve the ambiguity with the literals of MKS_Names
somehow (other names like e.g.

   type MKS_Names is (Meter_Unit, Kilogram_Unit, ...);

the latter would only be used in named associations of pragma Dimension, I
presume).

   pragma Dimension (Meter, Meter_Unit => 1);
   pragma Dimension (Newton, Meter_Unit => 1, Kilogram_Unit => 1,
                             Second_Unit => -2);

This look promising (but of course too late for now).

****************************************************************

From: Edmond Schonberg
Date: Thursday, November 19, 2010  9:52 AM

> I like this proposal. I presume that the compiler will have to create some
> hidden discriminants (like my SI units package) for unit checking during
> compile time, but discriminants will not exist in the executable code.

Actually the data structures are internal to the compiler, and discriminants
are never mentioned, but the net result is a compile-time check on assignments
and parameter passing that would be equivalent to discriminant checks (if those
were performed statically).

> However I would not recommend using unit symbol names for constants like
>   m : constant Length := 1.0;
> because they are case sensitive and Ada is not. Apex is well known for
> automatically choosing capitalized style resulting in changing mS
> (Millisiemens) in Ms (Megaseconds).

I would like to use short names for the basic units in each system. Name clashes
are the responsibility of the programmer, and there is always named notation to
disambiguate multiple potentially use-visible entities.  Hopefully milliSiemens
and Megaseconds are not declared in the same package, but for less frequently
used names it seems acceptable to spell them  out in full.

...
> This look promising (but of course too late for now).

There is no intent to make this part of the forthcoming Amendment to the
language:  2 pragmas do not an AI make!   My proposal is to implement this in
GNAT in the coming months, so that it is available for experimentation.
Standardization can wait until it is polished by usage. Many thanks for your
feedback!

****************************************************************

From: Christoph Grein
Date: Thursday, November 19, 2010  11:43 PM

> There is no intent to make this part of the forthcoming Amendment to
> the language:

Of course not, I did understand that.

>2 pragmas do not an AI make!

But there really is more in it than just two innocent-looking pragmas.

> My proposal is
> to implement this in GNAT in the coming months, so that it is
> available for experimentation. Standardization can wait until it is
> polished by usage. Many thanks for your feedback!

Could you please post your proposal here in full as soon as it approaches a
certain stage so that it can be "polished" early? I'm sure you will get lots of
feedback. I could imagine that this is the way to go with physical units.

****************************************************************

From: Randy Brukardt
Date: Wednesday, February 10, 2010  12:01 AM

> It references a paper by Hilfinger, "An Ada package for Dimensional
> Analysis" in ACM Transactions on Programming Languages and Systems,
> vol 10(2), April 1988.

Amazingly (or maybe not, as I don't throw stuff out easily), I have this
particular ACM TOPLAS issue on my bookshelf. The article in question is the
first one in the issue, ahead of one by Nicholas Wirth (where he defines
type extensions - cool).

He proposes a relatively simple units package. Here is a sample (transcribed by
hand, so any errors are probably mine):

   package Units is
       type Quant (D0, D1, D2, D3 : Integer := 0) is record
           V : Float;
       end record;
       -- Convinient abbreviations:
       subtype Scalar is Quant(0,0,0,0);
       Unit0 : constant Quant := (1,0,0,0,1.0);
       Unit1 : constant Quant := (0,1,0,0,1.0);
       Unit2 : constant Quant := (0,0,1,0,1.0);
       Unit3 : constant Quant := (0,0,0,1,1.0);

       -- Standard arithmetic:
       function "+" (L,R : Quant) return Quant;
       function "-" (L,R : Quant) return Quant;
       ...

       -- Coercions:
       function "/" (L,R : Quant) return String;
       function "+" (L : Scalar) return Float;
       function "-" (L : Scalar) return Float;

       -- Relationals:
       function "<" (L, R : Quant) return Boolean;
       ...

       -- Exceptions:
       -- Relationals, binary "+" and "-", and "/" yielding String
       -- raise Constraint_Error if L and R have different subtypes.

       pragma Inline (<all of the above>);

   end Units;

He goes on to show a sample implementation, and to discuss the fact that the
inlining involved will generally eliminate the unit checks by simple constant
propagation.

He eventually makes the extrodinary statement:

"Dimensions as types have no place in Ada because because they are
*definable* in Ada with no extra language features." (Emphasis his.)

He does back off of that statement a bit saying that compilers need to recognize
and optimize this construct well, and that will require some user "agitation".
That he certainly was right about (given that we are still discussing this 22
years later)!

Anyway, I agree with Jean-Pierre that this general approach is definitely one to
consider. Compilers *do* optimize discriminants already (and they have to be
able to handle discriminants not stored with the type in order to implement
Unchecked_Unions). So compilers *could* be able to construct these types without
any space overhead. Prreconditions and postconditions would allow expressing the
checks and resulting discriminants in the specifications of the operators.
Compilers would have to be smart enough to remove those checks (especially if
the discriminants are omitted from the in-memory representation), but I would
hope that they do that in any case. So it seems that only a bit of "help" is
needed to make a viable solution out of this. The only thing that I see as
clunky is the ugly aggregates to create values of the various types; perhaps a
little bit of syntactic sugar to make the aggregates read better would do the
trick?

****************************************************************


Questions? Ask the ACAA Technical Agent