measured icon indicating copy to clipboard operation
measured copied to clipboard

Compile-time units resolution

Open altavir opened this issue 4 years ago • 1 comments

Use compile-time units resolution in order to avoid number boxing.

The basic idea is the following:

  • Make Measurement an interface. And keep the implementation you already have for dynamic units.
  • Add an inline Measurement implementation like this:
inline class InlineMeasurement(<U: Units>(val value: Double): Measurement<U>
  • Add a resolver: inline fun <reified U:Units> resolveUnits(): Units and use it to load Units object when it is needed. The resolver could work in different ways. The simplest way is to load objectInstance from reflects.

Both implementations could be used in different cases: boxing one in cases, when the Units are dynamic, inline when you can infer everything in compile-time.

altavir avatar Jun 14 '20 08:06 altavir

This might be achievable by making Measure itself inline. Doing so would remove its ability to track the current unit, so its value would be in the "base" unit. This means:

val a = 60 * minutes

// a == Measure(60 * 60 * 1000), since minutes.ratio == 60000

All operations would be kept in the base unit:

val speed = 60 * miles / hours

// speed would be 0.0268224 m/ms (60 * 1609.344 / 3600000)
// Measured default Time unit is milliseconds

Everything else should work as it does now, with the exception of Measure.as(Unit) and Measure.toString(). The former wouldn't make sense anymore since Measure would never be in anything but base units. The toString behavior would need a new method; something like:

inline class Measure<T: Units>(val value: Double) {
    //...
    
    fun display(with: Units): String {...}

    //...
}

Unfortunately, inline classes are boxed whenever they are consumed as an interface they implement. So adding one would nullify the value of this change.

However, a major downside of exposing an inline class in the API is it requires consumers to have inline classes as part of their function signatures. Which prevents Java from calling them due to name mangling.

pusolito avatar Jun 15 '20 03:06 pusolito