Coder Social home page Coder Social logo

kunalsheth / units-of-measure Goto Github PK

View Code? Open in Web Editor NEW
92.0 4.0 3.0 2.77 MB

Type-safe dimensional analysis and unit conversion in Kotlin.

Home Page: http://units.kunalsheth.info

License: MIT License

Kotlin 100.00%
typesafe dimensional-analysis units-of-measure dsl

units-of-measure's People

Contributors

kunalsheth avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

units-of-measure's Issues

uom module fails first build with: Declaration annotated with '@OptionalExpectation' can only be used in common module sources

Since converting to a multiproject module, I am getting the following error when trying to build from a clean directory (./gradlew clean):

Declaration annotated with '@OptionalExpectation' can only be used in common module sources

I believe this is caused by the @JsName annotations.

It only happens on the first invocation of ./gradlew build, if I re-run ./gradlew build a second time everything compiles and runs fine.

This isn't a problem for development/testing on my workstation, but it is a problem for an automated build server. Have you seen this issue or have any ideas?

My module's build.gradle is:

apply plugin: 'org.jetbrains.kotlin.multiplatform'
apply plugin: 'info.kunalsheth.units.gradle'

repositories.mavenCentral()

kotlin {
    jvm()

    sourceSets {
        commonMain {
            kotlin.srcDirs += generateUnitsOfMeasure.generatedSrcDir
            dependencies { implementation kotlin('stdlib-common') }
        }
        jvmMain {
            dependsOn commonMain
            dependencies {
                implementation kotlin('stdlib')
            }
        }
        jvmTest {
            dependencies {
                implementation kotlin('test')
                implementation kotlin('test-junit')
                implementation "com.google.truth:truth:0.45"
            }
        }
        all {
            languageSettings.enableLanguageFeature('InlineClasses')
        }
    }
    targets.all {
        compilations.all { compileKotlinTask.dependsOn(generateUnitsOfMeasure) }
    }
}

// workaround for https://youtrack.jetbrains.com/issue/KT-27170
configurations {
    compileClasspath
}

apply from: 'units-of-measure.gradle'

Can this be used on android?

This looks like a very fascinating project, and I would like to try it out in an android app that I have to do a lot of unit conversion in. The configuration on the wiki, unfortunately, does not work for android.

I get

Could not get unknown property 'sourceSets' for root project

Is it possible to adjust the config to work on android?

How do I define Celsius and Fahrenheit?

UPDATE: DO NOT DO THIS. units-of-measure is incompatible with Celsius and Fahrenheit. Attempting to define Celsius and Fahrenheit will cause weird and incorrect behavior.

Celsius and Fahrenheit would have to be manually programmed in on the user's end. Celsius and Fahrenheit aren't "units" in the theoretical sense because they have different zeros.

To add Celsius and Fahrenheit, your code would look like the following:

inline val Number.Celsius get() = `Θ`(toDouble() + 273.15)
inline val `Θ`.Celsius get() = siValue - 273.15
object `Celsius` : UomConverter<`Θ`>,
        Quan<`Θ`> by box(1.Celsius) {
    override val unitName = "Celsius"
    override fun invoke(x: Double) = x.Celsius
    override fun invoke(x: `Θ`) = x.Celsius
}

inline val Number.Fahrenheit get() = `Θ`((toDouble() - 32) * 5 / 9 + 273.15)
inline val `Θ`.Fahrenheit get() = (siValue - 273.15) * 9 / 5 + 32
object Fahrenheit : UomConverter<`Θ`>,
        Quan<`Θ`> by box(1.Fahrenheit) {
    override val unitName = "Fahrenheit"
    override fun invoke(x: Double) = x.Fahrenheit
    override fun invoke(x: `Θ`) = x.Fahrenheit
}

IntelliJ can't seem to find the UOM code (i.e. everything is red)

Make sure your Gradle project is properly imported into IntelliJ:

  1. IntelliJ Menu Bar: View > Tool Windows > Gradle
  2. Gradle Tool Window: Sync
  3. Gradle Tool Window: [project name] > Tasks > unitsofmeasure > generateUnitsOfMeasure
  4. Gradle Tool Window: Sync
  5. open the generated UnitsOfMeasure.kt file in build/uoms directory of your units-of-measure Gradle module.
  6. wait for IntelliJ to finish lagging
  7. restart IntelliJ if necessary

Generated code not compiling

This library looks super cool and I wanted to try it out, but am coming across a problem in the generated code, where the compiler is complaining that '@JvmName' annotation is not applicable to this declaration.

There are too many errors to list all of them, but they are all of a similar nature. An example line where the compiler is complaining is:

@JvmName("L0A0M0T0I0Theta0N0J0_Divide_L0A0M0T0I0Theta0N0J0_generic")
operator fun `Dimensionless`.div(that: Quan<`Dimensionless`>) = `Dimensionless`(this.siValue / that.siValue)

Setup

src/main/kotlin/Main.kt

import info.kunalsheth.units.generated.*

fun main() {
    println(1.Metre)
}

build.gradle

plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.4.21'
    id 'info.kunalsheth.units' version '6.0.2'
}

repositories {
    mavenCentral()
}

sourceSets {
    main {
        java {
            srcDirs 'src/main/kotlin'
            srcDirs 'build/uom'
        }
    }
}

kilo syntax

In the demo there is code: val mass = 3.kilo(Gram), but When I try to do this, I get the following compile error:

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public val M /* = L0M1T0I0Theta0N0J0 /.Gram: Double defined in info.kunalsheth.units.generated
public val Number.Gram: M /
= L0M1T0I0Theta0N0J0 */ defined in info.kunalsheth.units.generated

I'm not sure why it can't pick between those 2 extension methods.

same for:
val speed = 65.Mile / Hour

It cannot figure out Hour

This is in a unit test in a kotlin/jvm library

Celsius, Fahrenheit, and Conversion.

I believe the issue of converting between Kelvin and Celsius/Fahrenheit is a perfectly solvable one, and I offer the overall approach I used to handle this:

// Static Properties of a Quantity
// e.g.
// object Velocity : Quantifiable<Velocity> { 
//     override dimension = Dimension(L = 1, T = -1)
//     override val baseUnit = Meter/Second
// }
interface Quantifiable<Q: Quantifiable<Q>> {
    val dimension: Dimension
    val baseUnit: BaseUnit<Q>
}

// An instance of a Quantifiable
// e.g. 11.Kelvin == Quantity(11, Kelvin)
// calculates amount in the base unit of the quantifiable for binary operations involving other quantities of the same quantifiable. e.g. 12.Kelvin + 25.Celsius == 12.Kelvin + (25.Celsius convertTo Kelvin)
class Quantity<Q : Quantifiable<Q>>(val amount: Double, val unit: MeasureUnit<Q> = baseUnit) : Quantifiable<Q> by unit.quantifiable {
    val baseAmount: Double by lazy { unit.convertToBase(amount) }
    operator fun compareTo(other: Quantity<Q>): Int = baseAmount.compareTo(other.baseAmount)
    operator fun plus(other: Quantity<Q>): Quantity<Q> = unit.convertFromBase(other.baseAmount + baseAmount)
    ...
}

// The units themselves hold the functions for converting to/from base unit.
// In this way, Celsius is 'defined' as Kelvin - 273.15, as seen below.
interface MeasureUnit<Q : Quantifiable<Q>> { // e.g. Kelvin
    val quantifiable: Q
    fun convertToBase(amount: Double): Double
    fun convertFromBase(baseAmount: Double): Double
}

// The base unit doesn't need to convert amounts to base. it's already base.
abstract class BaseUnit<Q : Quantifiable<Q>>(override val quantifiable: Q) : MeasureUnit<Q : Quantifiable<Q>> {
    override fun convertToBase(amount: Double) = amount
    override fun convertFromBase(baseAmount: Double) = baseAmount
}

// The following instances can be val instead of object. They were object for me because they were members of a sealed class
object Temperature : Quantifiable<Temperature> {
    override val dimension = Dimension= 1)
    override val baseUnit = Kelvin
}

object Kelvin : BaseUnit<Temperature> by BaseUnit(Temperature)
object Celsius : MeasureUnit<Temperature> {
    override val quantifiable = Temperature
    override fun convertToBase(amount: Double) = amount + 273.15
    override fun convertFromBase(baseAmount: Double) = amount - 273.15
}

Question about angles and radians

Hello there!

This is a cool library and I hope to see it developed more or at least have more community support on it!

I had a question about angles and radians within the library, and maybe I'm overthinking this. I have a function that accepts an angle, but internally the calculations are done in radians. I'm seeing if I could convert my code to use your library.

How would you write a function that does something like this into using your library? I've already got it compiled and working otherwise.

fun doMath(degrees: Double) {
    val radians = degrees * (Math.PI / 180.0)
    // Math that uses radians later
}

I was having a hard time figuring out what types I'd need to use from the library to replace the Double for the angle. It's assumed to be degrees currently.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.