Skip to content

Instantly share code, notes, and snippets.

@74hc595
Created June 11, 2014 04:09
Show Gist options
  • Save 74hc595/2b2ea9c8e86433f2ba42 to your computer and use it in GitHub Desktop.
Save 74hc595/2b2ea9c8e86433f2ba42 to your computer and use it in GitHub Desktop.
Experimenting with type-safe unit calculations in Swift
// Playground - noun: a place where people can play
import Cocoa
protocol UnitBase {
class var unitLabel:String { get }
}
// T: the unit
// U: its inverse
struct Unit<T:UnitBase,U:UnitBase> : Printable, Comparable {
var value:Double
init(_ v:Double) { value = v }
var description:String { return "\(value) \(T.unitLabel)" }
var inverse:Unit<U,T> { return Unit<U,T>(1/value) }
}
func == <T,U>(lhs:Unit<T,U>, rhs:Unit<T,U>) -> Bool { return lhs.value == rhs.value }
func <= <T,U>(lhs:Unit<T,U>, rhs:Unit<T,U>) -> Bool { return lhs.value <= rhs.value }
func >= <T,U>(lhs:Unit<T,U>, rhs:Unit<T,U>) -> Bool { return lhs.value >= rhs.value }
func < <T,U>(lhs:Unit<T,U>, rhs:Unit<T,U>) -> Bool { return lhs.value < rhs.value }
func > <T,U>(lhs:Unit<T,U>, rhs:Unit<T,U>) -> Bool { return lhs.value > rhs.value }
func + <T,U>(lhs:Unit<T,U>, rhs:Unit<T,U>) -> Unit<T,U> { return Unit<T,U>(lhs.value + rhs.value) }
func - <T,U>(lhs:Unit<T,U>, rhs:Unit<T,U>) -> Unit<T,U> { return Unit<T,U>(lhs.value - rhs.value) }
func * <T,U>(lhs:Double, rhs:Unit<T,U>) -> Unit<T,U> { return Unit<T,U>(lhs * rhs.value) }
func * <T,U>(lhs:Unit<T,U>, rhs:Double) -> Unit<T,U> { return Unit<T,U>(lhs.value * rhs) }
func / <T,U>(lhs:Double, rhs:Unit<T,U>) -> Unit<U,T> { return lhs * rhs.inverse }
func / <T,U>(lhs:Unit<T,U>, rhs:Double) -> Unit<T,U> { return Unit<T,U>(lhs.value / rhs) }
@assignment func += <T,U>(inout lhs:Unit<T,U>, rhs:Unit<T,U>) { lhs = lhs + rhs; }
@assignment func -= <T,U>(inout lhs:Unit<T,U>, rhs:Unit<T,U>) { lhs = lhs - rhs; }
@assignment func *= <T,U>(inout lhs:Unit<T,U>, rhs:Double) { lhs = lhs * rhs; }
@assignment func /= <T,U>(inout lhs:Unit<T,U>, rhs:Double) { lhs = lhs / rhs; }
struct RateBase: UnitBase { static var unitLabel = "Hz" }
struct DurationBase: UnitBase { static var unitLabel = "sec" }
typealias Rate = Unit<RateBase,DurationBase>
typealias Duration = Unit<DurationBase,RateBase>
extension Double {
var Hz:Rate { return Rate(self) }
var kHz:Rate { return Rate(self*1000) }
var sec:Duration { return Duration(self) }
var msec:Duration { return Duration(self*0.001) }
var min:Duration { return Duration(self*60) }
}
// the explicit description calls are due to a struct-printing bug in Xcode
(100.Hz).description
(44.1.kHz).description
(20.sec).description
(5000.msec).description
(3.min).description
(10.Hz + 20.Hz).description
(20.sec * 2).description
(3 * 4.sec).description
(2.min / 5).description
(1/10.sec).description
(1/20.Hz).description
(10.sec + 1/(3.Hz)).description
var t = 20.sec
t += 50.msec
t.description
// Won't compile
//3.sec + 2.Hz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment