{"action":"created","issue":{"url":"https://api.github.com/repos/Nadohs/Cast-Free-Arithmetic-in-Swift/issues/4","labels_url":"https://api.github.com/repos/Nadohs/Cast-Free-Arithmetic-in-Swift/issues/4/labels{/name}","comments_url":"https://api.github.com/repos/Nadohs/Cast-Free-Arithmetic-in-Swift/issues/4/comments","events_url":"https://api.github.com/repos/Nadohs/Cast-Free-Arithmetic-in-Swift/issues/4/events","html_url":"https://github.com/Nadohs/Cast-Free-Arithmetic-in-Swift/issues/4","id":112123500,"number":4,"title":"Improvement: removing extra cast to PreferredType and adding overflow arithmetic","user":{"login":"DevAndArtist","id":8276230,"avatar_url":"https://avatars.githubusercontent.com/u/8276230?v=3","gravatar_id":"","url":"https://api.github.com/users/DevAndArtist","html_url":"https://github.com/DevAndArtist","followers_url":"https://api.github.com/users/DevAndArtist/followers","following_url":"https://api.github.com/users/DevAndArtist/following{/other_user}","gists_url":"https://api.github.com/users/DevAndArtist/gists{/gist_id}","starred_url":"https://api.github.com/users/DevAndArtist/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DevAndArtist/subscriptions","organizations_url":"https://api.github.com/users/DevAndArtist/orgs","repos_url":"https://api.github.com/users/DevAndArtist/repos","events_url":"https://api.github.com/users/DevAndArtist/events{/privacy}","received_events_url":"https://api.github.com/users/DevAndArtist/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2015-10-19T11:10:30Z","updated_at":"2015-10-19T20:16:40Z","closed_at":null,"body":"Hello there,\r\n\r\nI found this repository through ***iosdevweekly issue 220*** and it was fun to dig into this kind of a topic. Before I watched your presentation I just wanted to try if I could solve the behavior by my self without knowing your code. It took me a few hours to figure out how to solve some problems but I finally had a working solution. I also faced the `+ 0` compiler issue as well while my research. At least I could remove the double casting (casting to the `PrefferedType`) overhead of your code with simple `protocol` abstraction:\r\n\r\n`lhs, rhs --> Double --> combine(lhs operator rhs) --> convert to T`\r\n\r\n is now \r\n\r\n`T(lhs) operator T(rhs)`\r\n\r\nI solved the comparison part by implementing a rule which will cast one of the type to match the other type. Btw. you can remove `Equatable` from your code because `Comparable` does inherit from that `protocol` already.\r\n\r\nHere is my implementation:\r\n```swift\r\nimport CoreGraphics\r\n\r\nprivate let rightTypeEqualsLeftType = true\r\n\r\nprotocol ConvertableIntegerType {\r\n\r\n\tinit(_ value: UInt8)\r\n\tinit(_ value: Int8)\r\n\tinit(_ value: UInt16)\r\n\tinit(_ value: Int16)\r\n\tinit(_ value: UInt32)\r\n\tinit(_ value: Int32)\r\n\tinit(_ value: UInt64)\r\n\tinit(_ value: Int64)\r\n\tinit(_ value: UInt)\r\n\tinit(_ value: Int)\r\n}\r\n\r\nextension ConvertableIntegerType {\r\n\t\r\n\tprivate init(_ value: ConvertableIntegerType) {\r\n\t\t\r\n\t\tswitch value {\r\n\t\t\t\r\n\t\tcase let number as UInt8:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Int8:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as UInt16:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Int16:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as UInt32:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Int32:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as UInt64:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Int64:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as UInt:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Int:\r\n\t\t\tself.init(number)\r\n\t\tdefault:\r\n\t\t\tfatalError(\"not convertable integer type\")\r\n\t\t}\r\n\t}\r\n}\r\n\r\nprotocol ConvertableFloatingPointType {\r\n\t\r\n\tinit(_ value: Float)\r\n\tinit(_ value: Double)\r\n\tinit(_ value: Float80)\r\n\tinit(_ value: CGFloat)\r\n}\r\n\r\nprotocol ConvertableNumberType: ConvertableIntegerType, ConvertableFloatingPointType {}\r\n\r\nextension ConvertableNumberType {\r\n\t\r\n\tprivate init(_ value: ConvertableNumberType) {\r\n\t\t\r\n\t\tswitch value {\r\n\t\t\t\r\n\t\tcase let number as UInt8:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Int8:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as UInt16:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Int16:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as UInt32:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Int32:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as UInt64:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Int64:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as UInt:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Int:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Float:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Double:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as Float80:\r\n\t\t\tself.init(number)\r\n\t\tcase let number as CGFloat:\r\n\t\t\tself.init(number)\r\n\t\tdefault:\r\n\t\t\tfatalError(\"not convertable number type\")\r\n\t\t}\r\n\t}\r\n}\r\n\r\nprotocol ArithmeticType: Comparable {\r\n\t\r\n\t@warn_unused_result\r\n\tfunc + (lhs: Self, rhs: Self) -> Self\r\n\t\r\n\t@warn_unused_result\r\n\tfunc - (lhs: Self, rhs: Self) -> Self\r\n\t\r\n\t@warn_unused_result\r\n\tfunc * (lhs: Self, rhs: Self) -> Self\r\n\t\r\n\t@warn_unused_result\r\n\tfunc / (lhs: Self, rhs: Self) -> Self\r\n\t\r\n\t@warn_unused_result\r\n\tfunc % (lhs: Self, rhs: Self) -> Self\r\n}\r\n\r\n// MARK: - ArithmeticNumberType\r\nprotocol ArithmeticNumberType: ConvertableNumberType, ArithmeticType {}\r\n\r\n@warn_unused_result\r\nfunc + <T: ArithmeticNumberType>(lhs: ConvertableNumberType, rhs: ConvertableNumberType) -> T {\r\n\r\n\treturn T(lhs) + T(rhs)\r\n}\r\n\r\n@warn_unused_result\r\nfunc - <T: ArithmeticNumberType>(lhs: ConvertableNumberType, rhs: ConvertableNumberType) -> T {\r\n\t\r\n\treturn T(lhs) - T(rhs)\r\n}\r\n\r\n@warn_unused_result\r\nfunc * <T: ArithmeticNumberType>(lhs: ConvertableNumberType, rhs: ConvertableNumberType) -> T {\r\n\t\r\n\treturn T(lhs) * T(rhs)\r\n}\r\n\r\n@warn_unused_result\r\nfunc / <T: ArithmeticNumberType>(lhs: ConvertableNumberType, rhs: ConvertableNumberType) -> T {\r\n\t\r\n\treturn T(lhs) / T(rhs)\r\n}\r\n\r\n@warn_unused_result\r\nfunc % <T: ArithmeticNumberType>(lhs: ConvertableNumberType, rhs: ConvertableNumberType) -> T {\r\n\t\r\n\treturn T(lhs) % T(rhs)\r\n}\r\n\r\n// MARK: - Comparable\r\n@warn_unused_result\r\nfunc == <T1: ArithmeticNumberType, T2: ArithmeticNumberType>(lhs: T1, rhs: T2) -> Bool {\r\n\t\r\n\treturn rightTypeEqualsLeftType ? lhs == T1(rhs) : T2(lhs) == rhs\r\n}\r\n\r\n@warn_unused_result\r\nfunc != <T1: ArithmeticNumberType, T2: ArithmeticNumberType>(lhs: T1, rhs: T2) -> Bool {\r\n\t\r\n\treturn !(lhs == rhs) // Comparable does not contain != function\r\n}\r\n\r\n@warn_unused_result\r\nfunc < <T1: ArithmeticNumberType, T2: ArithmeticNumberType>(lhs: T1, rhs: T2) -> Bool {\r\n\t\r\n\treturn rightTypeEqualsLeftType ? lhs < T1(rhs) : T2(lhs) < rhs\r\n}\r\n\r\n@warn_unused_result\r\nfunc > <T1: ArithmeticNumberType, T2: ArithmeticNumberType>(lhs: T1, rhs: T2) -> Bool {\r\n\t\r\n\treturn rightTypeEqualsLeftType ? lhs > T1(rhs) : T2(lhs) > rhs\r\n}\r\n\r\n@warn_unused_result\r\nfunc <= <T1: ArithmeticNumberType, T2: ArithmeticNumberType>(lhs: T1, rhs: T2) -> Bool {\r\n\t\r\n\treturn rightTypeEqualsLeftType ? lhs <= T1(rhs) : T2(lhs) <= rhs\r\n}\r\n\r\n@warn_unused_result\r\nfunc >= <T1: ArithmeticNumberType, T2: ArithmeticNumberType>(lhs: T1, rhs: T2) -> Bool {\r\n\t\r\n\treturn rightTypeEqualsLeftType ? lhs >= T1(rhs) : T2(lhs) >= rhs\r\n}\r\n\r\n// MARK: - OverflowArithmeticIntegerType\r\ninfix operator &/ { associativity left precedence 150 }\r\n\r\ninfix operator &% { associativity left precedence 150 }\r\n\r\nprotocol OverflowArithmeticIntegerType: ConvertableIntegerType, _IntegerArithmeticType {}\r\n\r\n@warn_unused_result\r\nfunc &+ <T: OverflowArithmeticIntegerType>(lhs: ConvertableIntegerType, rhs: ConvertableIntegerType) -> T {\r\n\t\r\n\treturn T.addWithOverflow(T(lhs), T(rhs)).0 // .0 containts the result and silently discard any overflow\r\n}\r\n\r\n@warn_unused_result\r\nfunc &- <T: OverflowArithmeticIntegerType>(lhs: ConvertableIntegerType, rhs: ConvertableIntegerType) -> T {\r\n\t\r\n\treturn T.subtractWithOverflow(T(lhs), T(rhs)).0\r\n}\r\n\r\n@warn_unused_result\r\nfunc &* <T: OverflowArithmeticIntegerType>(lhs: ConvertableIntegerType, rhs: ConvertableIntegerType) -> T {\r\n\t\r\n\treturn T.multiplyWithOverflow(T(lhs), T(rhs)).0\r\n}\r\n\r\n@warn_unused_result\r\nfunc &/ <T: OverflowArithmeticIntegerType>(lhs: ConvertableIntegerType, rhs: ConvertableIntegerType) -> T {\r\n\t\r\n\treturn T.divideWithOverflow(T(lhs), T(rhs)).0\r\n}\r\n\r\n@warn_unused_result\r\nfunc &% <T: OverflowArithmeticIntegerType>(lhs: ConvertableIntegerType, rhs: ConvertableIntegerType) -> T {\r\n\t\r\n\treturn T.remainderWithOverflow(T(lhs), T(rhs)).0\r\n}\r\n\r\n// MARK: - Extension\r\nextension UInt8: ArithmeticNumberType, OverflowArithmeticIntegerType {}\r\nextension Int8: ArithmeticNumberType, OverflowArithmeticIntegerType {}\r\nextension UInt16: ArithmeticNumberType, OverflowArithmeticIntegerType {}\r\nextension Int16: ArithmeticNumberType, OverflowArithmeticIntegerType {}\r\nextension UInt32: ArithmeticNumberType, OverflowArithmeticIntegerType {}\r\nextension Int32: ArithmeticNumberType, OverflowArithmeticIntegerType {}\r\nextension UInt64: ArithmeticNumberType, OverflowArithmeticIntegerType {}\r\nextension Int64: ArithmeticNumberType, OverflowArithmeticIntegerType {}\r\nextension UInt: ArithmeticNumberType, OverflowArithmeticIntegerType {}\r\nextension Int: ArithmeticNumberType, OverflowArithmeticIntegerType {}\r\n\r\nextension Float: ArithmeticNumberType {}\r\nextension Double: ArithmeticNumberType {}\r\n\r\nextension CGFloat: ArithmeticNumberType {\r\n\t\r\n\tinit(_ value: CGFloat) {\r\n\t\t\r\n\t\tself = value\r\n\t}\r\n\t\r\n\tinit(_ value: Float80) {\r\n\t\t\r\n\t\tself.init(Double(value))\r\n\t}\r\n}\r\n\r\nextension Float80: ArithmeticNumberType {\r\n\t\r\n\tinit(_ value: CGFloat) {\r\n\t\t\r\n\t\tself.init(Double(value))\r\n\t}\r\n}\r\n```\r\n\r\nI'd love to see in later Swift version some kind of dynamic cast like:\r\n ```swift\r\nlet newValue = value as! value.dynamicType\r\n``` \r\n\r\nso we could remove the `switch` overhead here.\r\n\r\nRegards Adrian Zubarev"},"comment":{"url":"https://api.github.com/repos/Nadohs/Cast-Free-Arithmetic-in-Swift/issues/comments/149333671","html_url":"https://github.com/Nadohs/Cast-Free-Arithmetic-in-Swift/issues/4#issuecomment-149333671","issue_url":"https://api.github.com/repos/Nadohs/Cast-Free-Arithmetic-in-Swift/issues/4","id":149333671,"user":{"login":"Nadohs","id":1163363,"avatar_url":"https://avatars.githubusercontent.com/u/1163363?v=3","gravatar_id":"","url":"https://api.github.com/users/Nadohs","html_url":"https://github.com/Nadohs","followers_url":"https://api.github.com/users/Nadohs/followers","following_url":"https://api.github.com/users/Nadohs/following{/other_user}","gists_url":"https://api.github.com/users/Nadohs/gists{/gist_id}","starred_url":"https://api.github.com/users/Nadohs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Nadohs/subscriptions","organizations_url":"https://api.github.com/users/Nadohs/orgs","repos_url":"https://api.github.com/users/Nadohs/repos","events_url":"https://api.github.com/users/Nadohs/events{/privacy}","received_events_url":"https://api.github.com/users/Nadohs/received_events","type":"User","site_admin":false},"created_at":"2015-10-19T20:16:40Z","updated_at":"2015-10-19T20:16:40Z","body":"If you have any ideas on fixing the issue above, would love to hear them!"}}