Skip to content

Instantly share code, notes, and snippets.

@bentrengrove
Last active February 12, 2024 12:25
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save bentrengrove/9759a3fbb564d62e1e63f417c58a3895 to your computer and use it in GitHub Desktop.
Save bentrengrove/9759a3fbb564d62e1e63f417c58a3895 to your computer and use it in GitHub Desktop.
Sample code demonstrating using Kotlin for type safe unit conversion
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}")
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)
@ilya-g
Copy link

ilya-g commented May 23, 2017

How comes that you multiply Distance by Distance and get Distance in result?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment