
Dimensional Analysis in Programming Languages (2018) - breck
https://gmpreussner.com/research/dimensional-analysis-in-programming-languages
======
btrettel
> An important theorem in dimensional analysis is the Buckingham π theorem,
> which states that the laws of physics do not depend on the choice of a
> specific system of measurement.

That's not what the Buckinham pi theorem states. The Buckingham pi theorem is
a statement about the functional dependencies of dimensionally homogeneous
equations.
[https://en.wikipedia.org/wiki/Buckingham_%CF%80_theorem](https://en.wikipedia.org/wiki/Buckingham_%CF%80_theorem)

I guess the writer mirrored some language on Wikipedia which indicated that
the physical laws being independent of the choice of units is a consequence of
the theorem.

Anyway, I don't mean to detract from what otherwise appears to be an
interesting and comprehensive summary of dimensional homogeneity checking in
programming languages.

------
mckinney
Java provides exceptional dimensional and unit support via the Manifold
framework [1].

    
    
        Length distance = 100 mph * 3 hr;
        Force f = 5.2 kg m/s/s; // same as 5.2 N
        Mass infant = 9 lb + 8.71 oz;
    

[1] [https://github.com/manifold-
systems/manifold/tree/master/man...](https://github.com/manifold-
systems/manifold/tree/master/manifold-deps-parent/manifold-ext#unit-
expressions)

------
jlokier
I implemented this in C++ for a commercial game engine many years ago. Both
internally, and in the API used by games on top.

We used Emacs-Lisp to generate a collection of C++ classes with all of the
arithmetic operaters that were allowed, and only those. "friend" is your
friend for this in C++.

We mostly used floating point to represent values, but could also use integers
with scale factors (automatically applied in the operators), which is nearly
equivalent to fixed point.

For things where vectors made sense, 1d, 2d and 3d vector types were
available. So Position2d and Position3d.

Absolute and relative values were distinguished: You could substract two
absolutes to get a relative, but you couldn't add two absolutes. You could add
a relative to an absolute to get an absolute.

And for time intervals we used wraparound arithmetic and comparisons, like the
Linux kernel has the time_before() macro, so absolute times could continue
"growing" without overflow in a running game.

Using the classes looked like a bit like this:

    
    
        Position3d p1, p2;
        Direction3d d = p2 - p1;
    
        Absolute_Time t1, t2;
        Time_Interval t = t2 - t1;
    
        Velocity3d v;
        object.set_position(p1 + t * v);
    

These types were used pervasively throughout all the game engine, gameplay
logic, "AI" and so on.

The constraints provided great type-checking and effectively documented a lot
of code as well.

This being a game engine, they had to be fast. So they were all inline
methods, in classes containing just a number, or up to 3 numbers for vectors.

Using GNU C++ this compiled down to the same machine code as if we hand-coded
the arithmetic in the traditional way; we checked. So there was no runtime
cost.

It was very satisfying to use.

------
stellalo
Julia has the Unitful.jl package for handling units:
[https://github.com/PainterQubits/Unitful.jl](https://github.com/PainterQubits/Unitful.jl)

~~~
dunefox
This looks worse than the Java units:

    
    
        julia> 1u"kg" == 1000u"g"             # Equivalence implies        unit conversion
        true
    

Java:

    
    
        Length distance = 100 mph * 3 hr;

~~~
sents
You can do this:

    
    
        julia> using Unitful.DefaultSymbols
    
        julia> 50m / s
        50 m s^-1

~~~
ChrisRackauckas
And you can manually define them:

    
    
      const m = u"m"
      50m
    

There's actually nothing special in the compiler for unit implementation. This
is just using the fact that `2x` is valid Julia code, where now x is something
that overloads a dispatch to turn the number into a number with units. By
default it uses string macros to keep the namespace clear, but you can fill
the namespace with whatever you want.

------
jakeogh
pint wrapper that does fuzzy matching:
[https://github.com/jakeogh/unitcalc](https://github.com/jakeogh/unitcalc)

    
    
       unitcalc 50stones kg
       unitcalc 1lightyear nm
       unitcalc 7fortnights decades
       unitcalc 99mi/sec fathom/month
       unitcalc 3.14radians/fortnight degrees/ms
       unitcalc 0.2W eV/century
       unitcalc 0.2J/ns ton_TNT/month
    

Pint is excellent. If you put in units that need a dimension to convert, the
exception says what is missing, it could ask for that value, but havent
figured it out yet; obviously dont want to parse the exception message.

The framework to tell it physics exists, so stuff like:

    
    
       unitcalc 0.2eV femtograms
    

should be possible.

------
brandmeyer
Reynolds Number, Prandtl number, power factor, efficiency, anything that is a
fraction of full range, mechanical strain, etc.

There are many terms in an engineering project that are unitless. Having a
system to automatically check the units on the remaining scalars is cute, but
doesn't do anything to prevent you from improperly performing operations that
relate efficiency and power factor by accident, for example.

Multi-input, multi-output control systems regularly assemble state vectors out
of terms that have mixed units. You can easily have amps, volts, meters per
second, and radians per second in the same mathematical vector.

I have yet to see a compile-time unit-checking scheme that adequately
addressed those issues.

~~~
mckinney
Can you provide an example involving "operations that relate efficiency and
power factor by accident" or similar? I'd like to better understand your
problem domain.

~~~
brandmeyer
That's kindof like asking for an example of operations that relate length and
speed by accident.

The whole point is that it is an accident. Its exactly the kind of accident
that embedding units into your type system is supposed to prevent. I just find
that the kind of trivial examples that folks support this way are just that -
trivial examples. They don't scale to the kinds of problems that I am faced
with solving.

------
stared
I think dimensions in physics serve as some interesting types, with their
built-in arithmetics.

I miss them in the languages I use (Python, TypeScript). I would love to have
e.g. "percent" or "probability" type. So that when "100 percent === 1
probability", with proper autocasting. Same for quite a few other qualities
(e.g. logit -(softmax)-> probabilities).

Before I get "just use Haskell" or something in that line. IMHO for anything
practical, ecosystem >>> language syntax and stuff. So the question is: are
there any solid Python or TypeScript approaches for these systems?

~~~
leni536
Probability is unitless. Percent is just literally 0.01 . Angle units have a
similar problem.

~~~
stared
I think you missed the point.

Units != dimensions.

E.g. angle in radians, degrees and full rotations differs by a factor. It is a
typical, and common, mistake that would benefit from such system.

------
nemoniac
From the Linux command line, you can use units(1):

    
    
        $ units "firkin furlong per fortnight"
                Definition: 5.6659503e-06 m^4 / s
        $

------
pron
Also worth mentioning is the Units Checker [1] for Java, which uses Java 8+'s
pluggable type systems feature to introduce units as intersection types.

[1]: [https://checkerframework.org/manual/#units-
checker](https://checkerframework.org/manual/#units-checker)

------
gumby
Since this was written a library proposal to add units to C++ has been
submitted to wg21: [http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2019/p193...](http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2019/p1935r0.html)

------
philzook
I wonder to what degree dimensional analysis and free theorems are connected.
The rabbit out of the hat style reasoning feels very similar to me. I suppose
one could use polymorphic type variables as units with the appropriate
definitions of arithmetic operations. I don't suppose anyone has a reference
on this?

------
quantified
Thank you for the pointers.

A system of units is hobbled without including the necessary counts of
objects/measurement events, which is open-ended. Mass per person is different
than mass per chicken or per 787, for example.

~~~
gugagore
I mean, yes. It's also incomplete if it doesn't include a notion of
directionality to e.g. distinguish between energy (force and displacement
aligned) and torque (force and displacement perpendicular).

The SI system isn't perfect, but expressing at least some dimensional
information to be checked by machine feels like a step in the right direction.

~~~
quantified
It certainly is. The more meaning we need to attach to a number, the more
expensive it is, and SI is a really good start.

------
mirekrusin
Good summary but why Julia is missing?

~~~
exdsq
Over the last week it seems Julia has become the new Lisp of HN.

~~~
shele
We rather do not call Julia a Lisp lest people notice.

------
aj7
I believe it’s well developed in LabView.

------
dnautics
> If you've used strongly-typed programming languages before, the relationship
> between dimensional analysis and type theory is rather obvious

Author clearly hadn't tried multiplying a user-input time value with a time
constant (like milliseconds) in Go, a strongly typed language

~~~
dunefox
Also *statically typed.

