I’m not saying your proposal would not be useful, but in the case of all of 
your examples, there are solutions that can be implemented now that might be 
better than just creating a new-type-but-exactly-the-same.

> On 5 Jan 2016, at 16:11, Grzegorz Adam Hankiewicz via swift-evolution 
> <[email protected]> wrote:
> 
> The other day I was reading about 
> https://www.reddit.com/r/swift/comments/3zbk64/type_math/

The idea of having a different type for each unit of distance is just wrong. 
You have one type for Distance with a value in a canonical unit and properties 
that extract the value in different units e.g

struct Distance
{
    let m: Double // SI unit of distance
    var km: Double { return m / 1000 }
    var cm: Double { return m * 100 }
    var miles: Double { return km * 0.62 }
}

Then you only need one set of addition and subtraction operators. You would 
also have multiplication by a dimensionless constant yielding a Distance and 
multiplication of two Distances yielding an Area.


> struct SomeTable {
>    var primaryKey: Int64
>    var otherTableForeignKey: Int64
>    var yeatAnotherForeginKey: Int64
> }
> 
> Unfortunately the types can be mixed, one can assign the value from 
> otherTableForeignKey to primaryKey without impunity.
> Using the reddit proposed struct as separate type would help here:
> 
>    public struct RefTablePk {
>        private let value: Int64
>    }
> 
>    public struct SomeTablePk {
>        private let value: Int64
>    }
> 
>    struct RefTable {
>        var primaryKey: RefTablePk
>    }
> 
>    struct SomeTable {
>        var primaryKey = SomeTablePk(value: 0)
>        var otherTableForeignKey = RefTablePk(value: 0)
>    }
> 
>    var a = SomeTable()
>    a.primaryKey = SomeTablePk(value: 3)
>    a.otherTableForeignKey = a.primaryKey // Fails, good!
>    print(a.primaryKey.value)

That all looks fine except, why not take advantage of nested types:

struct SomeTable
{
    struct PrimaryKey { let value: Int }

    var primaryKey: PrimaryKey
    var refTableId: RefTable.PrimaryKey
}

> 
> So far so good. The solution gets more hairy when one attempts to use such 
> fake types for mathematical operations

Why would you want to do mathematical operations on the primary key of a table? 
Primary keys obviously need to be Equatable and possibly Comparable (except 
what if the database uses a GUID as its key) but that is about it.

>    public struct Euros {
>        private let value: Double
>    }
> 
>    public struct Dollars {
>        private let value: Double
>    }
> 
>    var account = Euros(value: 100)
>    var bill = Euros(value: 42)
>    account = account - bill
> 
> The last line won’t compile: Binary operator ‘-‘ cannot be applied to two 
> ‘Euros’ operands.

How about a Currency protocol?

protocol Currency
{
    // value in smallest unit of currency e.g. EUR = cents, GBP = pence
    var rawValue: Int64 { get }
    init(rawValue: Int64)
}

func -<T: Currency>(a: T, b: T) -> T
{
    return T(rawValue: a.rawValue - b.rawValue)
}

struct EUR: Currency
{
    var rawValue: Int64
}

struct USD: Currency
{
    var rawValue: Int64
}

let foo = EUR(rawValue: 2000)
let bar = EUR(rawValue: 1000)

let baz = foo - bar // compiles

let whizz = USD(rawValue: 4000)

let biz = baz - whizz // error: binary operator '-' cannot be applied to 
operands of type 'EUR' and 'USD'

Only one - operator needs to be defined for all currencies and the fact that 
EUR and USD are intended to model currencies is self documenting.

So I don’t think any of your examples are compelling evidence for your 
proposal. That’s not to say there are not good reasons for it, I just haven’t 
seen them yet.

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to