Last active
February 12, 2024 12:25
-
-
Save bentrengrove/9759a3fbb564d62e1e63f417c58a3895 to your computer and use it in GitHub Desktop.
Sample code demonstrating using Kotlin for type safe unit conversion
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val miles = 1.kilometers.to(Distance.Mile) | |
val kilometers = 1.miles.to(Distance.Kilometer) | |
val total = 2.kilometers + 1.miles + 10.meters + 1.centimeter + 1.millimeter | |
Log.d("MainActivity", "Total distance is ${total.meters.amount} meters") | |
val totalTime = 2.hours + 2.minutes + 2.seconds + 2.milliseconds | |
Log.d("MainActivity", "Total time is ${totalTime.amount} ${totalTime.unit}") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open class Unit(val name: String, val ratio: Double) { | |
fun convertToBaseUnit(amount: Double) = amount * ratio | |
fun convertFromBaseUnit(amount: Double) = amount / ratio | |
} | |
open class Quantity<T: Unit>(val amount: Double, val unit: T) { | |
fun to(unit: T): Quantity<T> { | |
val baseUnit = this.unit.convertToBaseUnit(amount) | |
return Quantity(unit.convertFromBaseUnit(baseUnit), unit) | |
} | |
operator fun plus(quantity: Quantity<T>): Quantity<T> { | |
val converted = quantity.to(this.unit).amount | |
val amount = this.amount + converted | |
return Quantity(amount, this.unit) | |
} | |
operator fun minus(quantity: Quantity<T>): Quantity<T> { | |
val converted = quantity.to(this.unit).amount | |
val amount = this.amount - converted | |
return Quantity(amount, this.unit) | |
} | |
operator fun times(quantity: Quantity<T>): Quantity<T> { | |
val converted = quantity.to(this.unit).amount | |
val amount = this.amount * converted | |
return Quantity(amount, this.unit) | |
} | |
operator fun div(quantity: Quantity<T>): Quantity<T> { | |
val converted = quantity.to(this.unit).amount | |
val amount = this.amount / converted | |
return Quantity(amount, this.unit) | |
} | |
} | |
class Distance(name: String, ratio: Double) : Unit(name, ratio) { | |
companion object Factory { | |
val Mile = Distance("Mile", 1.60934 * 1000.0) | |
val Kilometer = Distance("Kilometer", 1000.0) | |
val Meter = Distance("Meter", 1.0) | |
val Centimeter = Distance("Centimeter", 0.01) | |
val Millimeter = Distance("Millimeter", 0.001) | |
} | |
} | |
val Quantity<Distance>.miles get() = this.to(Distance.Mile) | |
val Quantity<Distance>.kilometers get() = this.to(Distance.Kilometer) | |
val Quantity<Distance>.meters get() = this.to(Distance.Meter) | |
val Quantity<Distance>.centimeters get() = this.to(Distance.Centimeter) | |
val Quantity<Distance>.millimeters get() = this.to(Distance.Millimeter) | |
val Number.meters: Quantity<Distance> get() = Quantity(this.toDouble(), Distance.Meter) | |
val Number.kilometers: Quantity<Distance> get() = Quantity(this.toDouble(), Distance.Kilometer) | |
val Number.miles: Quantity<Distance> get() = Quantity(this.toDouble(), Distance.Mile) | |
val Number.centimeter: Quantity<Distance> get() = Quantity(this.toDouble(), Distance.Centimeter) | |
val Number.millimeter: Quantity<Distance> get() = Quantity(this.toDouble(), Distance.Millimeter) | |
class Time(name: String, ratio: Double) : Unit(name, ratio) { | |
companion object Factory { | |
val Hour = Time("Hour", TimeUnit.HOURS.toMillis(1L).toDouble()) | |
val Minute = Time("Minute", TimeUnit.MINUTES.toMillis(1L).toDouble()) | |
val Second = Time("Second", TimeUnit.SECONDS.toMillis(1L).toDouble()) | |
val Millisecond = Time("Millisecond", 1.0) | |
} | |
} | |
val Quantity<Time>.hours get() = this.to(Time.Hour) | |
val Quantity<Time>.minutes get() = this.to(Time.Minute) | |
val Quantity<Time>.seconds get() = this.to(Time.Second) | |
val Quantity<Time>.milliseconds get() = this.to(Time.Millisecond) | |
val Number.hours: Quantity<Time> get() = Quantity(this.toDouble(), Time.Hour) | |
val Number.minutes: Quantity<Time> get() = Quantity(this.toDouble(), Time.Minute) | |
val Number.seconds: Quantity<Time> get() = Quantity(this.toDouble(), Time.Second) | |
val Number.milliseconds: Quantity<Time> get() = Quantity(this.toDouble(), Time.Millisecond) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How comes that you multiply Distance by Distance and get Distance in result?