[swift-evolution] Epic: Typesafe calculations

Félix Cloutier felixcca at yahoo.ca
Thu Jan 7 13:26:16 CST 2016


I was thinking of a C++ design using variadic templates. I'm pretty sure you (as in "someone else") could do it. I don't have anything to show at the moment because I'd probably pull my hair for hours given my know-how level. However, I think that each individual step outlined would be feasible and I don't think that I'm missing any.

You have unit integral constants (Meters = 1, Seconds = 2, Kilograms = 3, etc), a UnitProduct integer sequence (UnitProduct<Meters, Meters, Seconds> being m^2 * s), and a UnitQuotient template that has two UnitProduct template arguments (UnitQuotient<UnitProduct<Meter>, UnitProduct<Second, Second>> being m/s^2, or m * s^-2). Finally, you have a Quantity type that has a numeric type for the quantity and a UnitQuotient for the unit.

The Quantity type has operator overloads for additions and subtractions to the same type. It also has multiplication and division operators for numeric types and any Quantity.

When you multiply two quantities, you merge the UnitProduct integer sequences of the two UnitQuotients. You order them (to give units a canonical order) and you "cancel out" (omit) template arguments that are in both the denominator and numerator. When you divide them, you just merge one UnitQuotient's denominator with the other's numerator and vice-versa.

Complex units can be typedef'd. For intermediate results, type inference would be enough.

Given that it relies on variadic templates and non-type template arguments, this wouldn't be feasible in Swift at the moment.

Félix

> Le 7 janv. 2016 à 13:46:09, Thorsten Seitz via swift-evolution <swift-evolution at swift.org> a écrit :
> 
> Really great to hear that you are planning for Swift to be able to do these kinds of things!
> 
> I tried to see how far I could get (working from memory of a Haskell library; Boost.Units seems quite similar at first glance), but failed of course because of the missing parameterized recursive typealiases:
> 
> import Foundation
> 
> public protocol Peano {}
> public struct Zero : Peano {}
> public struct Succ<P : Peano> : Peano {}
> public struct Pred<S : Peano> : Peano {}
> public typealias One = Succ<Zero>
> public typealias Two = Succ<One>
> public typealias MinusOne = Pred<Zero>
> public typealias MinusTwo = Pred<One>
> 
> // Quantity with SI Units
> 
> // TODO: extend by more type parameters for the remaining SI units
> public struct Quantity<Length: Peano, Time: Peano, Mass: Peano> : 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)
> }
> 
> // Missing language feature: parameterized recursive typealias
> // i.e. the following typealiases are currently not possible
> typealias Add<Zero, P: Peano> = P
> typealias Add<P: Peano, Zero> = P
> typealias Add<Succ<P1>, Succ<P2>> = Add<Succ<Succ<P1>>,P2>
> typealias Add<Succ<P1>, Pred<P2>> = Add<P1,P2>
> typealias Add<Pred<P1>, Succ<P2>> = Add<P1,P2>
> typealias Add<Pred<P1>, Pred<P2>> = Add<P1,Pred<Pred<P2>>>
> 
> typealias Sub<Zero, P: Peano> = P
> typealias Sub<P: Peano, Zero> = P
> typealias Sub<Succ<P1>, Succ<P2>> = Sub<P1,P2>
> typealias Sub<Succ<P1>, Pred<P2>> = Sub<P1,Pred<Pred<P2>>
> typealias Sub<Pred<P1>, Succ<P2>> = Sub<Pred<Pred<P1>>,P2>
> typealias Sub<Pred<P1>, Pred<P2>> = Sub<P1,P2>
> 
> public func *
>     <L1,T1,M1,L2,T2,M2,L,T,M where
>     L == Add<L1,L2>, T == Add<T1,T2>, M == Add<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 == Sub<L1,L2>, T == Sub<T1,T2>, M == Sub<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<Zero, Zero, Zero> // dimensionless
> public typealias Length   = Quantity<One, Zero, Zero> // meter
> public typealias Time     = Quantity<Zero, One, Zero> // seconds
> public typealias Mass     = Quantity<Zero, Zero, One> // kilogram
> public typealias Velocity = Quantity<One, MinusOne, Zero> // m/s
> public typealias Newton   = Quantity<One, MinusTwo, One> // 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
> 
> 
>> Am 31.12.2015 um 18:25 schrieb Dave Abrahams via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>>:
>> 
>>> 
>>> On Dec 25, 2015, at 4:43 PM, Nickolas Pohilets via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>> If Swift would support non-type generic parameters, then I would like to have Boost.Unit library (http://www.boost.org/doc/libs/1_60_0/doc/html/boost_units.html <http://www.boost.org/doc/libs/1_60_0/doc/html/boost_units.html>) available in Swift.
>> 
>> Yes, that’s an excellent design.  We really want to do this when we get the necessary language features (I hope we might also come up with some that improve readability a bit over what you can do in C++).
>> 
>>> 
>>> 2015-12-25 4:36 GMT+01:00 Stephen Christopher via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>>:
>>> I have been working for a couple weeks (since the previous [newtype discussion](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001821.html <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001821.html>) ) on a related pitch. There seem to me to be multiple ways to solve this problem - a newtype(esque) keyword, struct subtyping, or forwarding as Matthew is suggesting. I’d hoped to have a discussion starter out before the holidays, but it takes a fair amount of work to put together even a decent draft for a proposal. This is top of my list currently for a way to contribute though. Looking forward to the ensuing discussions.
>>> 
>>> Thanks for the pointer on class delegation. I’ve looked at delegated properties there (which came up in relation to Joe’s recent proposal for behaviors on properties).
>>> 
>>> - Step Christopher
>>> 
>>> 
>>> 
>>> On Thu, Dec 24, 2015 at 2:40 PM, Matthew Johnson via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>> 
>>> Sent from my iPad
>>> 
>>> > On Dec 24, 2015, at 1:07 PM, Tino Heth <2th at gmx.de <mailto:2th at gmx.de>> wrote:
>>> >
>>> >
>>> >> I'm planning to write a proposal for automatic forwarding.
>>> > Something like class delegation in Kotlin?
>>> > Please hurry, I've no work to distract me for the rest of the year, and extending typealias could be a very quick proposal ;-)
>>> 
>>> Details are still brewing.  I am not familiar with class delegation in Kotlin but will look it up.  Thanks for mentioning it!
>>> 
>>> I plan to spend a lot of time on Swift proposal work over the next week and a half but can't make any promises on timing.  I made that mistake with my proposal on flexible memberwise initialization which ended up taking a couple weeks longer than I expected (for several reasons).  What I can say is that this is pretty high on my Swift proposal priority list.
>>> 
>>> Matthew
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>> 
>>>  
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>> 
>>> 
>>>  _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> -Dave
>> 
>>  _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>  _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160107/bd52a850/attachment.html>


More information about the swift-evolution mailing list