Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/nacular/measured
Intuitive, type-safe units of measure
https://github.com/nacular/measured
kotlin library mpp units units-of-measure
Last synced: 4 days ago
JSON representation
Intuitive, type-safe units of measure
- Host: GitHub
- URL: https://github.com/nacular/measured
- Owner: nacular
- License: mit
- Created: 2018-10-19T00:42:03.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2024-06-18T04:15:23.000Z (5 months ago)
- Last Synced: 2024-08-02T09:27:05.197Z (3 months ago)
- Topics: kotlin, library, mpp, units, units-of-measure
- Language: Kotlin
- Homepage: https://nacular.github.io/measured
- Size: 799 KB
- Stars: 152
- Watchers: 7
- Forks: 5
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-kotlin-multiplatform - Measured - Intuitive, type-safe units of measure. (Libraries / Utility)
README
Measured: intuitive, type-safe units
[![Kotlin 1.9.23](https://img.shields.io/badge/Kotlin_1.9.23-blue.svg?style=for-the-badge&logo=kotlin&logoColor=white)](http://kotlinlang.org)
[![JS, Wasm, JVM, iOS, Android, Native](https://img.shields.io/badge/JS%2C_Wasm%2C_JVM%2C_iOS%2C_Android%2C_Native-purple?style=for-the-badge&logo=kotlin&logoColor=white)](https://kotlinlang.org/docs/js-overview.html)
[![License: MIT](https://img.shields.io/badge/MIT_License-green.svg?style=for-the-badge)](https://github.com/nacular/measured/blob/master/LICENSE)Measured provides a safe and simple way to work with units of measure. It uses the compiler to ensure correctness, and provides intuitive, mathematical operations to work with any units. This means you can write more robust code that avoids implicit units. Time handling for example, is often done with implicit assumptions about milliseconds vs microseconds or seconds. Measured helps you avoid pitfalls like these.
```kotlin
interface Clock {
fun now(): Measurefun handleUpdate(duration: Measure
fun update(clock: Clock) {
val startTime = clock.now()//...
handleUpdate(clock.now() - startTime)
}fun reportTimeInMillis(time: Double) {}
```## Complex Units
Use division and multiplication to create compound measures. Convert between these safely and easily with the `as` and `in` methods.
```kotlin
val velocity = 5 * meters / seconds
val acceleration = 9 * meters / (seconds * seconds)
val time = 1 * minutes// d = vt + ½at²
val distance = velocity * time + 1.0 / 2 * acceleration * time * timeprintln(distance ) // 16500 m
println(distance `as` kilometers) // 16.5 km
println(distance `as` miles ) // 10.25262467191601 miprintln(5 * miles / hours `as` meters / seconds) // 2.2352 m/s
```The `as` method converts a `Measure` from its current `Unit` to another. The result is another `Measure`. While `in` returns the magnitude of a `Measure` in the given `Unit`.
## Avoid Raw Values
Measure's support of math operators helps you avoid working with raw values directly.
```kotlin
// typealias Velocity = UnitRatio defined in the libraryval marathon = 26 * miles
val velocity = 3 * kilometers / hours
val timeToRunHalfMarathon = (marathon / 2) / velocity // 6.973824 hrfun calculateTime(distance: Measure, velocity: Measure): Measure
## Extensible
You can easily add new conversions to existing units and they will work as expected.
```kotlin
val hands = Length("hands", 0.1016) // define new Length unitval l1 = 5 * hands
val l2 = l1 `as` meters // convert to Measure with new unitval v: Measure = 100_000 * hands / hours
println("$l1 == $l2 or ${l1 `in` meters}") // 5.0 hands == 0.508 m or 0.508
println(v `as` hands / seconds) // 27.77777777777778 hands/s
println(v `as` miles / hours ) // 6.313131313131313 mi/hr
```You can also define entirely new units with a set of conversions and have them interact with other units.
```kotlin
// Define a custom Units type
class Blits(suffix: String, ratio: Double = 1.0): Units(suffix, ratio) {
operator fun div(other: Blits) = ratio / other.ratiocompanion object {
// Various conversionsval bloop = Blits("bp" ) // the base unit
val blick = Blits("bk", 10.0)
val blat = Blits("cbt", 100.0)
}
}// Some typealiases to help with readability
typealias BlitVelocity = UnitsRatio
typealias BlitAcceleration = UnitsRatio>val m1: Measure = 5 * blat / (seconds * seconds)
val m2: Measure = m1 * 10 * minutes
val m3: Measure> = m2 / (5 * blick)
```## Current Limitations
Measured uses Kotlin's type system to enable compile-time validation. This works really well in most cases, but there
are things the type system currently does not support. For example, `Units` and `Measures` are **order-sensitive**.```kotlin
val a: UnitsProduct = radians * seconds
val b: UnitsProductNotice the types for a and b are different.
This can be mitigated on a case by case basis with explicit extension functions that help with order. For example,
you can ensure that `kg` is sorted before `m` by providing the following extension.```kotlin
// ensure Mass comes before Length when Length * Mass
operator fun Length.times(mass: Mass) = mass * thisval f1 = 1 * (kilograms * meters) / (seconds * seconds)
val f2 = 1 * (meters * kilograms) / (seconds * seconds)// f1 and f2 now have the same type
```You can also define an extension on Measure to avoid needing parentheses around kilograms and meters.
```kotlin
// ensure Mass comes before Length when Measure multiplied by Mass
operator fun Measure.times(mass: Mass) = amount * (units * mass)
```Measured currently only supports linear units where all members of a given unit are related by a single magnitude. This
applies to many units, but Fahrenheit and Celsius are examples of temperature units that requires more than a multiplier
for conversion.## Installation
Measured is a Kotlin [Multi-platform](https://kotlinlang.org/docs/multiplatform-get-started.html) library that targets a wide range of platforms. Simply add a dependency to your app's Gradle build file as follows to start using it.
```kotlin
repositories {
mavenCentral()
}dependencies {
implementation("io.nacular.measured:measured:$VERSION")
}
```## Contact
- Please see [issues](https://github.com/nacular/measured/issues) to share bugs you find, make feature requests, or just get help with your questions.
- Let us know what you think by leaving a comment or a star ⭐️.