[swift-evolution] Epic: Typesafe calculations

Thorsten Seitz tseitz42 at icloud.com
Fri Jan 8 07:54:52 CST 2016


> Am 07.01.2016 um 20:26 schrieb Félix Cloutier <felixcca at yahoo.ca>:
> 
> Given that it relies on variadic templates and non-type template arguments, this wouldn't be feasible in Swift at the moment

Having non-type template arguments (and the ability to operate on them at compile time) would make it possible to drop all that stuff modeling this in the type system with peano numbers like I tried. Much more simple! 

This would reduce my example to the following (no need for variadic templates because I give each SI unit it fixed place in the parameter list — your idea of using variadic templates would probably allow to extend the system by new base units, though, and allow to cut down the long template parameter lists in the arithmetic functions which will grow longer with each base unit added in my example...):

// TODO: extend by more type parameters for the remaining SI units
// missing language feature: non-type generic arguments, here: Int
public struct Quantity<Length = Int, Time = Int, Mass = Int> : Equatable, Comparable {
    
    let value: Double
    
    init(_ value: Double) {
        self.value = value
    }
}

public func ==<L,T,M>(lhs: Quantity<L,T,M>, rhs: Quantity<L,T,M>) -> Bool {
    return lhs.value == rhs.value
}

public func <<L,T,M>(lhs: Quantity<L,T,M>, rhs: Quantity<L,T,M>) -> Bool {
    return lhs.value < rhs.value
}

public func +<L,T,M>(lhs: Quantity<L,T,M>, rhs: Quantity<L,T,M>) -> Quantity<L,T,M> {
    return Quantity<L,T,M>(lhs.value + rhs.value)
}

public func *
    <L1,T1,M1,L2,T2,M2,L,T,M where L == L1+L2, T == T1+T2, M == M1+M2>
    (lhs: Quantity<L1,T1,M1>, rhs: Quantity<L2,T2,M2>) -> Quantity<L,T,M>
{
    return Quantity<L,T,M>(lhs.value * rhs.value)
}

public func /
    <L1,T1,M1,L2,T2,M2,L,T,M where L == L1-L2, T == T1-T2, M == M1-M2>
    (lhs: Quantity<L1,T1,M1>, rhs: Quantity<L2,T2,M2>) -> Quantity<L,T,M>
{
    return Quantity<L,T,M>(lhs.value / rhs.value)
}


// Defining some nice typealiases with which to work

public typealias Scalar   = Quantity<0, 0, 0> // dimensionless
public typealias Length   = Quantity<1, 0, 0> // meter
public typealias Time     = Quantity<0, 1, 0> // seconds
public typealias Mass     = Quantity<0, 0, 1> // kilogram
public typealias Velocity = Quantity<1, -1, 0> // m/s
public typealias Newton   = Quantity<1, -2, 1> // m*kg/s^2


public extension Double {
    
    public var m: Length {
        return Length(self)
    }
    public var s: Time {
        return Time(self)
    }
    public var kg: Mass {
        return Mass(self)
    }
}

let dist = 10.m + 5.m
let time = 20.s
let mass = 5.kg
let velocity: Velocity = dist / time
let force: Newton = mass * dist / (time * time)


-Thorsten
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160108/accc17b5/attachment.html>


More information about the swift-evolution mailing list