I discovered the existence of this in F# just recently, and wondered how I could get it in Kotlin.
I considered using a design like Measure<Unit>
myself, but had issues with it after I tried to use it in something more complex. If you use large arrays/lists of values with units, you have to choose between two equally bad options - either store them as primitives and wrap them when the caller asks for one element, or store them as wrappers and take the extra memory hit. Either option eats into computation time, and in my ray tracer, the cost/benefit trade-off wasn’t too appealing.
The nice thing about how this works in F# is that, at runtime, the values are just primitives, so it shouldn’t perform any worse than an array of primitives with no unit information. And in the case of JVM at least, the vector API (still in incubation) is convenient only when working with primitive arrays (or perhaps buffers? I haven’t investigated) - if you have wrappers then you have to copy the values out into an array before passing them off, and the extra copying is enough overhead that it almost defeats the purpose of using the vector ops. (I know, because I used to store my doubles in an ImmutableList<Double>
, and switched to a custom ImmutableDoubleArray
for this exact reason.)
Anyway, you would think that inline classes would be one way to remove that overhead, sort of like how Compose’s Dp
works.
I use a similar strategy for my Angle
class because it was way too easy to screw up the units of angles when dealing with trigonometry. 8.degrees
or 8.radians
both return an Angle
which internally is always just storing radians, and then I just have my own version of all the trig functions… that worked cleanly - until I wanted to store a Complex
for an angle instead of a Double
. I haven’t introduced ComplexAngle
yet but it might happen… it won’t appear in public API so it isn’t as important.
The problem with trying to do inline classes for all types of measurement is that you then have expressions like 10.m / 5.s
which has to return 2 m/s somehow… so you end up with a million little inline classes for all possible combinations and all the methods for the operators returning the right inline class for the resulting units. And eventually, someone hits a combination which there is no class for yet, because nobody imagined someone would want something like m/s³.
I don’t know if any library is trying to use inline classes for this yet - all the ones I’ve seen so far have been normal wrapper/data classes.
So I too think that type annotations are probably the way to go about this. I just have no idea how to implement that. Whatever it is, it would have to allow me to annotate Double
, and DoubleArray
, and anything other custom class that might also be a container of doubles (like my own ImmutableDoubleArray
…)
Apologies for a bit of thread necromancy, but I thought it was better than creating a duplicate thread.