Units of Measure

You can do it in compile time with complicated generics like Value<T : Unit>. But I think it does not worth the time spent since in any case you will work with some user input that could not be checked in compile time.

It is very hard to do this compile safe with generics in the case of derived units such as m/s or m/s^2. Even in C++ with full templates it is very hard. The best solution would be to do it with manual overloads/extension functions and not allow division/multiplication of multi-unit values otherwise.

A couple of articles

http://bentrengrove.com/blog/2017/5/21/fun-with-types-extensions-and-generics-in-kotlin

http://javanut.net/2017/05/23/more-fun-with-generics-in-kotlin/

1 Like

The struggle in jvm based languages with a units system is balancing the desire to have compile units checking (I can’t assign a length to a variable meant to hold time) vs. wanting to keep it lightweight (not having every value be a full blown object on the heap). There is no way to have both in Java 9 and this can only be solved with value objects which are part of Project Valhalla.

One thing to be careful of when defining a type-safe units system is that you want to focus on what the quantity is meant to represent not the units used for the quantity. So Length and Time are different quantities and thus different types. Centimeters and Inches are different ways to create and extract a Length quantity and are not type incompatible. This is analagous to the way a date in Java is an instant in time. There are not different date types for each time zone.

I think it’s more than just that, even if you’re willing to create objects for quantities that associate a number with a unit the generics get really complicated really fast with derived units of derived units of derived units and so on. There is a JSR to add units to the JVM, it creates objects and cannot infer units at compile time. I think the only reason is the impracticality of very complex generic types, I think this can be remedied with type aliases. Basically you only define base units and dimensions for example: Length and Time. Then speed is DerrivedDimension<Length, Time>, similar to the example in the second link @fvasco provided. And the only way you explicitly define speed is with a typealias Speed = DerrivedDimension<Length, Time>. However I do not think it is possible to do this in a way that is compatible with JSR-363 (not sure how important that is).

The plus side is I do think it is possible to make a clean implementation of a statically checked inferred units library for Kotlin using typealias and in a way that should work across all targets. Of course until value types are added there will be extraneous object creation. I made Kotlin extensions for uom-se and I’m currently using that as a units library, this was not very much work because most of the work is done in the underlying Java library. I would eventually like to make a Kotlin specific units library that is statically checked for inferred units and leverages typealias but I think this would be a ton of work to do well (if it is indeed possible to implement well at all) so hopefully someone else does this :slight_smile:

I was just reading the following page: Units of measure | F# for fun and profit and the last paragraph states:

Units of measure at runtime
An issue that you may run into is that units of measure are not part of the .NET type system.

F# does stores extra metadata about them in the assembly, but this metadata is only understood by F#.

This means that there is no (easy) way at runtime to determine what unit of measure a value has, nor any way to dynamically assign a unit of measure at runtime.

It also means that there is no way to expose units of measure as part of a public API to another .NET language (except other F# assemblies).

So, I thought that maybe the information about units of measure should not be entirely based on generics, instead utilizing annotations, or maybe it is possible to combine generics and annotations in some sensible way? Could annotation processors help making this work during compile time? I have never used them myself.

@Unit(meter / second^2)
val acceleration = 2.0

@Unit(second)
val time = 10.0

val speed = acceleration * time

speed.unit  // meter / second

@Unit(pascal)
val pressure = 10.0

speed + pressure  // Runtime unit error, ideally we'd like to check this at compile time (annotation processors?)

What you are talking about is the pre-processor and a complex one.You can type check variables declarations (you can do it with generics as well), but what about expressions? You will either have to annotate any expression results by hand or perform full language analysis.
What I don’t understand is why do you need it? What advantages does static check have? If you want to check types without calculating expression then just make calculations lazy. It requires pretty little, just two-component object containing units and lambda-expression.

1 Like

Well, I wrote down some thoughts about types.
https://blog.lastsys.com/2017/05/04/types-representing-meaning-instead-of-storage/

I also found that this book Search captures the applications of my evolution of thoughts after having the opportunity to taste what is being done in Idris, Haskell, Scala, and so on.

The advantage of static checks is to reduce the number of tests. The IDE can give better advice. It also helps a lot when doing refactoring.

Hello,
I’ve attempted to create such a thing for my robotics team.
It is able to represent arbitrary dimensional analysis in a type-safe manner.

https://github.com/kunalsheth/units-of-measure

Please tell me if you have any feedback.

The Manifold Java plugin adds comprehensive Unit Expression support.

Mass m = 10 kg;

Length distance = 65 mph * 3.2 hr;

Force force = 82.023 kg m/s/s;

etc.

Also unit expressions go beyond units e.g., Ranges:

for (int i: 1 to 10 step 2) {...}

How is this relevant for kotlin? I thought Manifold was for java and not kotlin.

Kotlin and Java are interoperable, no?

Re Kotlin specifically, there is an ongoing effort to support Manifold via kotlinc compiler plugin, the same way Manifold works with Java as a javac plugin. We’re getting there!

Also, the link covers a pretty cool language feature (binding expressions) that could benefit any language willing to implement it. This post looked like a good spot to spark a conversation.

In any case there are other links in this discussion covering other languages’ take on units (F#, Scala). What’s wrong with posting how manifold is doing it with Java?

Previous discussion on unit of measure: Units of Measure - #10 by lastsys

The usual way to handle this in Kotlin would be extension properties so instead of saying 10 cm as you can with manifold it would be 10.cm.

Some existing attempts to solve this problem:

https://www.kotlinresources.com/library/ktunits/

How would you do this with a compound unit such as:

5 kg m/s/s

or

1.5M USD // 1.5 million usd

More to the point, unit operations are not really specific to units per se. For instance, the Manifold Range API defines to, step, etc.

for (Mass m: 10kg to 100kg step 5r) {...}

The “empty” operator is similar to using the “infix” functionality in Kotlin, but is arguably more flexible.

I am merely pointing to other places where this has been discussed. I have no idea if these stack up to manifold, but I will point to this documentation for the first library (http://units.kunalsheth.info/) which shows some unit math like 100.Mile / Hour

Nice. Thanks!

Yes, but that does not mean that you can use compiler plugins from java for kotlin. Normal java code works with kotlin, but compiler plugins for java and kotlin something completly different. You would need to write a completely different plugin for kotlin than for java.

I couldn’t find any. There is an issue on github about it, but it doesn’t seem like there is any work done. Also there isn’t even a stable or documented API for compiler plugins for kotlin so I’d be really surprised if there was anything done yet.

Nothing directly. But the OP only provided those links to explain what he wanted. Whenever someone else mentioned another solution from a programming language it was in combination with how this could be applied to kotlin, which you didn’t.
If you meant to say that one solution would be to change kotlin to allow for such expressions (e.g. by creating a compiler plugin) than I’m sorry that I didn’t understand you.

The compiler plugin is more about generating code. In this case one would need to amend the grammar. It is certainly possible to make a Kotlin derived language but that wouldn’t be Kotlin, nor is it, as far as I understand, the goal of Kotlin plugins to support doing that.

The javac plugin “API” is no more capable or documented than the kotlinc API. Java’s is designed so a plugin can listen to compiler before/after events for parsing, type attribution, and so forth (just as with annotation processing), which ain’t much, but it doesn’t take much. Really just about any hook into the compiler is enough to fully exploit it. It’s just a matter of “hacking” at that point. As you can imagine the Manifold plugin has to hook into and override parts of the compiler to achieve seamless integration, which of course is far outside the scope of intentions for the javac plugin API, but there it is. You can argue about whether or not Java is still Java in this context, but really, what does that matter? What does matter are the new capabilities offered by such a plugin, how useful they are to you, and the level of support available in your development environment.

Anyhow there is progress with the kotlinc Manifold “plugin”, but it’s slow going and limited to Manifold’s core tech, type manifolds – unit expressions and other language augmentations will never see the light of day in Kotlin. It’s a private repo (as is the Manifold Intellij repo), but that doesn’t mean they don’t exist.

What you need is actually a ‘unit type’ accompanying an expression.
That ‘unit type’ is composed of two lists of base types one for numerators and one for denominators.
In addition you have to support algebra of multiplication and division on those ‘unit types’.
and example for a multiplication:
meter/(secondsecond) X kgsecond → meter*kg/second
This unit type has to be checked for compatibility when performing operation or assignment.
For example: 1meter - 3seconds → ERROR

this can be achieved by defining a new type that holds a numeric value and the ‘unit type’.
Implement it’s operators for type checking and unit algebra.
Implement it’s setter for type checking.

Actually we’re doing something like that in a language for autonomous vehicle checking called M-SDL.