[swift-evolution] [Idea] Typed Numerics
Vladimir.S
svabox at gmail.com
Tue Aug 23 11:00:50 CDT 2016
On 23.08.2016 12:42, Nur Ismail wrote:
> Hi Vladimir,
>
> Thanks for your code, it's actually quite close to what I want :)
>
> Some comments:
> 1) The main downside is that to read back the value, one can't re-use ".m",
> ".km", etc. and have to use ".inMeters()", etc. Would have been nice to be
> able read and write using the same suffixes.
I agree with all of your points. And about this first.. Yes, I think this
variant is better:
struct Distance {
var km : Double { return self.m / 1000.0 }
var m: Double
var mm : Double { return self.m * 1000.0 }
init(m: Double) {
self.m = m
}
init(km: Double) {
self.m = km * 1000.0
}
init(mm: Double) {
self.m = mm / 1000.0
}
static func +(lhs: Distance, rhs: Distance) -> Distance {
return Distance(m: lhs.m + rhs.m)
}
static func -(lhs: Distance, rhs: Distance) -> Distance {
return Distance(m: lhs.m - rhs.m)
}
}
extension Double {
var km : Distance { return Distance(km: self) }
var m : Distance { return Distance(m: self) }
var mm : Distance { return Distance(mm: self) }
}
let dist : Distance = 10.km + 5.m + 5.mm
print(dist.m) // 10005.005
print(dist.km) // 10.005005
print(MemoryLayout<Distance>.size) // 8
>
> 2) Works quite well on assigning values, and works as expected with a lot
> of control of allowed operations, etc. However can make things verbose as
> you also mentioned when needing to define many different types, but that's
> a limitation of Swift not supporting this "Typed Numerics" natively rather
> than your code :)
>
> 3) Requires an extra byte to store the enumeration value internally, so
> whereas Double is 8 bytes, Distance would be 9 bytes. Sometimes it might be
> desirable to store the original type the value was assigned with, for
> example .km, and only convert to appropriate type when reading, whereas
> other times it's best to convert immediately to the preferred type on
> assignment which would be .m (or meters) in this case, perhaps use the
> "default" keyword next to the type?. Also compiler support would be
> advantageous here also, so that constant expressions can be evaluated at
> compile time with no overhead, so that if I put... let dist : Distance =
> 125.km <http://125.km>, dist is converted at compile time to 125000.m.
>
> 4) Agree that this "feature" should rather be a type alias, as we dealing
> with types rather than a structure.
>
> 5) If Swift could support the shortened typed numeric syntax natively, and
> with the efficiency that can only happen in the compiler itself so that it
> works as fast and efficiently as normal untyped numbers that would be
> awesome :)
>
> 6) I think a feature like this could make Swift even more useful in
> scientific and other critical applications where they deal with many
> different types of numbers, such as velocity, acceleration, gravity, power,
> watts, distance, etc. etc.
>
> Also normal everyday code, for example,
> func circle(radius: Double) ... //Is that radius in pixels, meters,
> millimetres or something else? But if radius was defined as our fancy
> Distance (assuming we add pixels (px) too :), then they could call it with:
> circle(radius: 150.px) //or
> circle(radius: 100.mm <http://100.mm>) //or
> circle(radius: 10.cm <http://10.cm>)
> //etc.
>
> This would help make the code clearer, and lead to better quality code and
> hopefully less bugs.
>
> Regards,
> Nur
>
> On Mon, Aug 22, 2016 at 6:07 PM, Vladimir.S <svabox at gmail.com
> <mailto:svabox at gmail.com>> wrote:
>
> The first question is what the meaning of , for example, a
> multiplication of Distance ? I.e.
> let x1 : Distance = 10.m
> let x2 : Distance = 10.km <http://10.km>
> let x3 = x1 * x2 // ???
>
> I.e. as soon as your Distance is Double, you allows all kind of
> floating point operations on instances of this type. And some such
> operations has no meaning for Distance. So, in your proposal, you need
> to somehow control allowed operations.
>
> And I believe you can get what you want right now with enums(If I'm not
> missing something):
>
> enum Distance {
> case km(Double)
> case m(Double)
> case mm(Double)
>
> func inKilometers() -> Double {
> return inMeters() / 1000.0
> }
>
> func inMeters() -> Double {
> switch self {
> case .km(let value) : return value * 1000.0
> case .m(let value) : return value
> case .mm(let value) : return value / 1000.0
> }
> }
>
> func inMillimeters() -> Double {
> return inMeters() * 1000.0
> }
>
> static func +(lhs: Distance, rhs: Distance) -> Distance {
> return .m(lhs.inMeters() + rhs.inMeters())
> }
>
> static func -(lhs: Distance, rhs: Distance) -> Distance {
> return .m(lhs.inMeters() - rhs.inMeters())
> }
>
> // implement needed operations here..
> }
>
> extension Double {
> var km : Distance { return Distance.km(self) }
> var m : Distance { return Distance.m(self) }
> var mm : Distance { return Distance.mm(self) }
> }
>
> let dist : Distance = 10.km <http://10.km> + 5.m + 5.mm <http://5.mm>
>
> print(dist.inMeters()) // 10005.005
> print(dist.inKilometers()) // 10.005005
>
> More verbose, but more control. From other point of view, currently
> you'll need a lot of code for each such type(like Distance).
>
> But I do think that such ability to create custom domain-specific types
> based on standard value types is a useful feature which can improve a
> quality of code and can reduce the number of bugs.
>
> The syntax to declare such type should be simple and clear, to be able
> to declare a number of such types without a lot of boilerplate code.
> Something like this:
>
> typealias Distance : Double {
> var km : Distance { return self * 1000.0 }
> var m : Distance { return self }
> var mm : Distance { return self / 1000.0 }
> inherit [+,-,/]
> }
>
> IMO such type is more a type alias than new structure
>
> On 22.08.2016 17 <tel:22.08.2016%2017>:54, Nur Ismail via
> swift-evolution wrote:
>
> Hi,
>
> I'm new to the list, but have an idea for Typed Numerics.
> Basically numeric values (such as Double, Int, etc.) that are strongly
> typed to a specific use case, for example Distance, Weight, etc.
> and cannot
> be intermixed with untyped values.
>
> So if I have (the syntax is made up, but perhaps something like this):
> =====
> //Distance
> struct fixedtype Distance : Double {
> var km: …
> var m: …
> typealias meters: m
> var feet: ...
> ...
> }
>
> //Weight
> struct fixedtype Weight : Double {
> var kg: …
> var g: …
> typealias grams : g
> var pound: ...
> }
>
> …
> var weight : Weight = 5.kg <http://5.kg> <http://5.kg/> + 5.g + 7.m
> ………………………………………..^ Compiler Error: Can’t add Distance to Weight...
> var distance: Distance = 7.km <http://7.km> <http://7.km/> + 12.5.m
> + 5.0 + 3
> ………………………………………………...^ Compiler Error: can’t add untyped number to
> Distance...
> ===
>
> The main restriction this syntax should do is disallow intermixing of
> numeric types (even if they all descend from Double, Int, etc.) and not
> allow adding untyped numerics (i.e. those without a type suffix),
> unless
> explicitly asked for in the code.
>
> Any of these can be converted to it's raw untyped value, for example:
> =====
> let number : Double = distance.rawValue + 5.0 //This is allowed
> distance += number.m //number is converted to m (meters)
> =====
>
> >From the Swift 3 Language guide, we are for example given the following
> example:
> =====
> extension Double {
> var km: Double { return self * 1_000.0 }
> var m: Double { return self }
> var cm: Double { return self / 100.0 }
> var mm: Double { return self / 1_000.0 }
> var ft: Double { return self / 3.28084 }
> }
>
> let aMarathon = 42.km <http://42.km> <http://42.km/> + 195.m
> print("A marathon is \(aMarathon) meters long")
> // Prints "A marathon is 42195.0 meters long"
> =====
>
> This is quite nice to suffix a conversion method after the value,
> but if I
> had another extension that converts the values to pounds and kilograms,
> then one can illegally do this:
> let aValue = 42.km <http://42.km> <http://42.km/> + 195.m +
> 17.pounds + 5.0
> and then the code would still compile and run, but not work as
> intended.
>
> Extra reading, and inspiration for a feature like the above:
> Mars Probe Lost Due to Simple Math Error
> http://articles.latimes.com/1999/oct/01/news/mn-17288
> <http://articles.latimes.com/1999/oct/01/news/mn-17288>
> <http://articles.latimes.com/1999/oct/01/news/mn-17288
> <http://articles.latimes.com/1999/oct/01/news/mn-17288>>
>
> "NASA lost its $125-million Mars Climate Orbiter because spacecraft
> engineers failed to convert from English to metric measurements when
> exchanging vital data before the craft was launched, space agency
> officials
> said Thursday.
>
> A navigation team at the Jet Propulsion Laboratory used the metric
> system
> of millimeters and meters in its calculations, while Lockheed Martin
> Astronautics in Denver, which designed and built the spacecraft,
> provided
> crucial acceleration data in the English system of inches, feet and
> pounds.
>
> As a result, JPL engineers mistook acceleration readings measured in
> English units of pound-seconds for a metric measure of force called
> newton-seconds."
>
>
> _______________________________________________
> 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>
>
>
More information about the swift-evolution
mailing list