Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
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 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