Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile-time units resolution #2

Open
altavir opened this issue Jun 14, 2020 · 1 comment
Open

Compile-time units resolution #2

altavir opened this issue Jun 14, 2020 · 1 comment

Comments

@altavir
Copy link

altavir commented Jun 14, 2020

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.

@pusolito
Copy link
Collaborator

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants