Skip to content

Instantly share code, notes, and snippets.

@alandvgarcia
Forked from bentrengrove/Sample.kt
Created July 22, 2020 11:31
Show Gist options
  • Save alandvgarcia/fd98df96cdbacb6db6c3e9380de0d95c to your computer and use it in GitHub Desktop.
Save alandvgarcia/fd98df96cdbacb6db6c3e9380de0d95c 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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment