SIMD3 Extension with default implementations - swift

I have a few protocols for vectors used across my app. They have some default implementations in extensions, so that I can have all added functionality implemented for all types of vectors. Now I would like to extend SIMD3 with Scalar == Double, to implement Vector3D protocol. Swift is telling me that if I specify type of Scalar in extension, then I need to also add all dependencies of Vector3D for this type. I don't know why this is not happening automatically when I choose associated type of SIMD3, but ok. So now I have something like this:
import UIKit
import simd
protocol DividableByInt {
static func / (lhs: Self, rhs: Int) -> Self
}
protocol HasBasicinitializer {
init()
}
protocol BasicMathOperations {
static func + (lhs: Self, rhs: Self) -> Self
static func - (lhs: Self, rhs: Self) -> Self
static func * (lhs: Self, rhs: Self) -> Self
static func / (lhs: Self, rhs: Self) -> Self
}
protocol Vector: BasicMathOperations, DividableByInt, HasBasicinitializer {
associatedtype Scalar: (SIMDScalar & FloatingPoint)
static var zero: Self { get }
static func calculate(_ lhs: Self, _ rhs: Self, _ operation: (Scalar, Scalar) -> Scalar) -> Self
static func calculate(_ lhs: Self, _ rhs: Scalar, _ operation: (Scalar, Scalar) -> Scalar) -> Self
func allAxesValues() -> [Scalar]
}
extension Vector {
static func + (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, +) }
static func - (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, -) }
static func * (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, *) }
static func / (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, /) }
static func * (lhs: Self, rhs: Scalar) -> Self { return calculate(lhs, rhs, *) }
static func / (lhs: Self, rhs: Scalar) -> Self { return calculate(lhs, rhs, /) }
static func / (lhs: Self, rhs: Int) -> Self { return calculate(lhs, Scalar(rhs), /) }
}
protocol Vector3D: Vector {
init(x: Scalar, y: Scalar, z: Scalar)
var x: Scalar { get }
var y: Scalar { get }
var z: Scalar { get }
}
extension Vector3D {
func allAxesValues() -> [Scalar] {
return [x, y, z]
}
static func calculate(_ lhs: Self, _ rhs: Self, _ operation: (Scalar, Scalar) -> Scalar) -> Self {
return Self(x: operation(lhs.x, rhs.x), y: operation(lhs.y, rhs.y), z: operation(lhs.z, rhs.z))
}
static func calculate(_ lhs: Self, _ rhs: Scalar, _ operation: (Scalar, Scalar) -> Scalar) -> Self {
return Self(x: operation(lhs.x, rhs), y: operation(lhs.y, rhs), z: operation(lhs.z, rhs))
}
}
extension SIMD3: Vector3D where Scalar == Double {}
extension SIMD3: HasBasicinitializer {}
extension SIMD3: DividableByInt where Scalar == Double {}
extension SIMD3: Vector where Scalar == Double {
static let zero = SIMD3(x: 0.0, y: 0.0, z: 0.0)
}
extension SIMD3: BasicMathOperations where Scalar == Double {}
Everything works automatically, except the last one thing:
extension SIMD3: BasicMathOperations where Scalar == Double {}
The compiler says:
Type 'SIMD3<Scalar>' does not conform to protocol 'BasicMathOperations'
But since I added
extension SIMD3: Vector where Scalar == Double
it should have all needed methods implemented already, and be able to proceed. Protocol DividableByInt is inherited almost in the same way, and it can work with the implementation from Vector extension. Why is that BasicMathOperations can't use methods implemented in Vector extension?
I know I could resolve this by adding
extension SIMD3: BasicMathOperations where Scalar == Double {
static func + (lhs: SIMD3, rhs: SIMD3) -> SIMD3 { return calculate(lhs, rhs, +) }
static func - (lhs: SIMD3, rhs: SIMD3) -> SIMD3 { return calculate(lhs, rhs, -) }
static func * (lhs: SIMD3, rhs: SIMD3) -> SIMD3 { return calculate(lhs, rhs, *) }
static func / (lhs: SIMD3, rhs: SIMD3) -> SIMD3 { return calculate(lhs, rhs, /) }
}
but I don't want to double this code, since it's already implemented in extension Vector, and it should be used from there place instead.
In the end I just want to extend SIMD3 to implement Vector3D. If needed with Scalar == Double or for any type of Scalar of possible.
Looks like the problem is because SIMD3 already has implemented functions like +, -, /, * and compiler can't determine which one to choose. I could remove default implementation from Vector and this would resolve the issue for SIMD3, but then I would need to separately implement it for all other types that conforms to Vector. Im using this also for SCNVector3 and CGPoint. I don't know what is better. Maybe there is some better solution, so that I can just have this implemented for all other types but SIMD3?

OK I think I have found one better solution. I moved default implementation of BasicMathOperations from extension Vector to separate protocol, and then I added inheritance to this new protocol to all types that conform to Vector, except for SIMD3.
// Adds default implementation for BasicMathOperation
protocol VectorWithDefaultImplementationForBasicMathOperations: Vector {}
extension VectorWithDefaultImplementationForBasicMathOperations {
static func + (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, +) }
static func - (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, -) }
static func * (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, *) }
static func / (lhs: Self, rhs: Self) -> Self { return calculate(lhs, rhs, /) }
}
extension CGPoint: VectorWithDefaultImplementationForBasicMathOperations {}
extension SCNVector3: VectorWithDefaultImplementationForBasicMathOperations {}
If anyone know better solution, please let me know, but I think this is already pretty fine.

Related

Code repetitiveness when writing custom extensions

I pretty often encounter situation like this:
public extension CountableRange {
func advanced(by n: Bound.Stride) -> Self {
let lowerBound = self.lowerBound.advanced(by: n)
let upperBound = self.upperBound.advanced(by: n)
return .init(uncheckedBounds: (lowerBound, upperBound))
}
static func + (lhs: Self, rhs: Bound.Stride) -> Self {
lhs.advanced(by: rhs)
}
static func - (lhs: Self, rhs: Bound.Stride) -> Self {
lhs.advanced(by: -rhs)
}
}
//--------------------------------------------------------
public extension CountableClosedRange {
func advanced(by n: Bound.Stride) -> Self {
let lowerBound = self.lowerBound.advanced(by: n)
let upperBound = self.upperBound.advanced(by: n)
return .init(uncheckedBounds: (lowerBound, upperBound))
}
static func + (lhs: Self, rhs: Bound.Stride) -> Self {
lhs.advanced(by: rhs)
}
static func - (lhs: Self, rhs: Bound.Stride) -> Self {
lhs.advanced(by: -rhs)
}
}
Absolutely identical two pieces of code. Is there any way to deal with it?
If CountableRange and CountableClosedRange have conformed to some common protocol BasicRange I could just write one extension for that BasicRange protocol. But often it's not the case.
You can use protocol default implementations to shared add functionality to several built-in types.
You simply need to declare a protocol and extend it with default implementations for the desired functions, then make the built-in types you want to have this functionality conform to the protocol and they'll get the default implementations for free.
public protocol BasicRange: RangeExpression where Bound: Strideable {
var lowerBound: Bound { get }
var upperBound: Bound { get }
init(uncheckedBounds bounds: (lower: Bound, upper: Bound))
func advanced(by n: Bound.Stride) -> Self
static func + (lhs: Self, rhs: Bound.Stride) -> Self
static func - (lhs: Self, rhs: Bound.Stride) -> Self
}
public extension BasicRange {
func advanced(by n: Bound.Stride) -> Self {
let lowerBound = self.lowerBound.advanced(by: n)
let upperBound = self.upperBound.advanced(by: n)
return .init(uncheckedBounds: (lowerBound, upperBound))
}
static func + (lhs: Self, rhs: Bound.Stride) -> Self {
lhs.advanced(by: rhs)
}
static func - (lhs: Self, rhs: Bound.Stride) -> Self {
lhs.advanced(by: -rhs)
}
}
extension CountableRange: BasicRange {}
extension CountableClosedRange: BasicRange {}
CountableRange(uncheckedBounds: (1,5)).advanced(by: 1)
CountableClosedRange(uncheckedBounds: (1,5)).advanced(by: 1)

Extend Int enum with comparison operators

Very often you have Int enums like this:
enum Difficulty: Int {
case Easy = 0
case Normal
case Hard
}
Difficulty values have a certain meaning and we may want to introduce order for them. For example, somewhere we need to compare:
let isBonusAvailable = level.difficulty.rawVAlue <= Difficulty.Hard.rawValue
I want to make this code a little bit shorter:
let isBonusAvailable = level.difficulty <= .Hard
It can be easily achieved if I add <= directly to the Difficulty. But I wanted to solve this problem in general, so I tried this super-tricky way:
protocol RawRepresentableByInt {
var rawValue: Int { get }
}
extension RawRepresentableByInt {
static func <(lhs: RawRepresentableByInt, rhs: RawRepresentableByInt) -> Bool {
return lhs.rawValue < rhs.rawValue
}
static func >(lhs: RawRepresentableByInt, rhs: RawRepresentableByInt) -> Bool {
return lhs.rawValue > rhs.rawValue
}
static func <=(lhs: RawRepresentableByInt, rhs: RawRepresentableByInt) -> Bool {
return lhs.rawValue <= rhs.rawValue
}
static func >=(lhs: RawRepresentableByInt, rhs: RawRepresentableByInt) -> Bool {
return lhs.rawValue >= rhs.rawValue
}
}
// Error: Extension of protocol 'RawRepresentable' cannot have an inheritance clause
extension RawRepresentable: RawRepresentableByInt where RawValue == Int {
}
It produces a compiler error:
Error: Extension of protocol 'RawRepresentable' cannot have an inheritance clause
I think there is nothing unimplementable in comparison of Int enum in term of logic. Please, help me to trick the Swift compiler. Anyone, who also need such extensions may participate.
It was easier than I thought. So, basically you can use Self instead of creating an additional protocol.
enum Difficulty: Int {
case Easy = 0
case Normal
case Hard
}
extension RawRepresentable where RawValue: Comparable {
static func <(lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue < rhs.rawValue
}
static func >(lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue > rhs.rawValue
}
static func <=(lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue <= rhs.rawValue
}
static func >=(lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue >= rhs.rawValue
}
}
let easy = Difficulty.Easy
print(easy > .Hard) // false

The right way to extend OptionSet with a constrained RawValue

I have an OptionSet for which I wanted to be able to perform bitwise operations (the operations in the BitwiseOperation protocol). I wrote an extension to my type, then realized I should make it reusable code. It took a while to figure out a way, and what I did was make a protocol that inherits from both protocols and adds a constraint on the associated type, then a protocol extension providing default implementations.
It works, but my question is this: Is this the best way to accomplish this?
protocol BitwiseOptionSet : BitwiseOperations, OptionSet {
associatedtype RawValue : BitwiseOperations, ExpressibleByIntegerLiteral
}
extension BitwiseOptionSet {
static var allZeros : Self {
return Self(rawValue: 0)
}
prefix static func ~(x: Self) -> Self {
return Self(rawValue: ~x.rawValue)
}
static func ^(lhs: Self, rhs: Self) -> Self {
return Self(rawValue: lhs.rawValue ^ rhs.rawValue)
}
static func &(lhs: Self, rhs: Self) -> Self {
return Self(rawValue: lhs.rawValue & rhs.rawValue)
}
static func |(lhs: Self, rhs: Self) -> Self {
return Self(rawValue: lhs.rawValue | rhs.rawValue)
}
}
You can extend OptionSet with a constraint on its RawValue:
extension OptionSet where RawValue: BitwiseOperations {
static var allZeros : Self {
return Self(rawValue: .allZeros)
}
prefix static func ~(x: Self) -> Self {
return Self(rawValue: ~x.rawValue)
}
static func ^(lhs: Self, rhs: Self) -> Self {
return Self(rawValue: lhs.rawValue ^ rhs.rawValue)
}
static func &(lhs: Self, rhs: Self) -> Self {
return Self(rawValue: lhs.rawValue & rhs.rawValue)
}
static func |(lhs: Self, rhs: Self) -> Self {
return Self(rawValue: lhs.rawValue | rhs.rawValue)
}
}
Note that requiring a conformance to ExpressibleByIntegerLiteral
can be avoided by using Self(rawValue: .allZeros) instead of
Self(rawValue: 0).
Example:
struct MyOptionSet: OptionSet {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
}
let a = MyOptionSet(rawValue: 3)
let b = MyOptionSet(rawValue: 5)
let c = a & b
print(c.rawValue) // 1

Switch Generic Numeric Function with Protocol

This is working great for Doubles and Floats. But getting other numerals like Ints involved is proving really difficult.
public protocol TemperatureConvertable: FloatLiteralConvertible, CustomStringConvertible {
func +(lhs: Self, rhs: Self) -> Self
func -(lhs: Self, rhs: Self) -> Self
func *(lhs: Self, rhs: Self) -> Self
func /(lhs: Self, rhs: Self) -> Self
}
extension Double: TemperatureConvertable {}
extension Float: TemperatureConvertable {}
public func fahrenheitToCelsius<T: TemperatureConvertable>(fahrenheit: T) -> T {
// (°F − 32) ÷ 1.8 =°C
return (fahrenheit - 32.0) / 1.8
}
public func celsiusToFahrenheit<T: TemperatureConvertable>(celsius: T) -> T {
// (°C × 1.8) + 32 =°F
return (celsius * 1.8) + 32.0
}
From what I can find there isn't a NumberLiteralConvertible or similar. And just creating a Numeric protocol like others suggest makes the arithmetic fail because the types don't match. Ideally I'd like something like this thats more generic but this I get Binary operator '-' cannot be applied to operands of type 'T' and 'Double' on the line of actual math for fahrenheit - 32.0 because the lhs and rhs aren't both Self.
public protocol TemperatureConvertable: CustomStringConvertible {
func +(lhs: Self, rhs: Self) -> Self
func -(lhs: Self, rhs: Self) -> Self
func *(lhs: Self, rhs: Self) -> Self
func /(lhs: Self, rhs: Self) -> Self
}
extension Int: TemperatureConvertable {}
extension Double: TemperatureConvertable {}
extension Float: TemperatureConvertable {}
public func fahrenheitToCelsius<T: TemperatureConvertable>(fahrenheit: T) -> T {
// (°F − 32) ÷ 1.8 =°C
return (fahrenheit - 32.0) / 1.8
}
public func celsiusToFahrenheit<T: TemperatureConvertable>(celsius: T) -> T {
// (°C × 1.8) + 32 =°F
return (celsius * 1.8) + 32.0
}
You need a way to create a TemperatureConvertable from a Double and viceversa.
So your functions will be able to internally use Double(s) to make the operations. And finally convert the result to T for the output.
Step 1
public protocol TemperatureConvertible: CustomStringConvertible {
// this part is not needed
// func +(lhs: Self, rhs: Self) -> Self
// func -(lhs: Self, rhs: Self) -> Self
// func *(lhs: Self, rhs: Self) -> Self
// func /(lhs: Self, rhs: Self) -> Self
init(_ other: Double)
var double: Double { get }
}
Now lets update your extensions to Double, Float and Int.
You don't need to add the initializer we declared above since these types already have it.
extension Int: TemperatureConvertible {
public var double: Double { return Double(self) }
}
extension Double: TemperatureConvertible {
public var double: Double { return self }
}
extension Float: TemperatureConvertible {
public var double: Double { return Double(self) }
}
Step 2
Now you can rewrite your functions like this
public func fahrenheitToCelsius<T: TemperatureConvertible>(fahrenheit: T) -> T {
// (°F − 32) ÷ 1.8 =°C
let celsius = (fahrenheit.double - 32.0) / 1.8
return T(celsius)
}
public func celsiusToFahrenheit<T: TemperatureConvertible>(celsius: T) -> T {
// (°C × 1.8) + 32 =°F
let fahrenheit = (celsius.double * 1.8) + 32.0
return T(fahrenheit)
}
Test
let celsius: Int = 20
let fahrenheit = celsiusToFahrenheit(celsius)
// ^ it's an Int
Tip
For readability and consistency with the Cocoa framework I suggest you to rename your functions like this
public func fahrenheitFromCelsius<T: TemperatureConvertible>(_ celsius: T) -> T
public func celsiusFromFahrenheit<T: TemperatureConvertible>(_ fahrenheit: T) -> T

Overloading Operators in Swift

I'm trying to implement the Comparable protocol in Swift, but the compiler doesn't like any of my attempts to overload the < operator. I've checked the Apple documents and all the SO posts, but none of them even compile. Xcode gives me this warning:
Consecutive declarations on a line must be separated by ';'
and it keeps recommending me to insert a semicolon after the less than symbol. Any insight on what I'm doing wrong is appreciated.
class SomeClass: NSObject, Equatable, Comparable{
var number: UInt32!
override init()
{
super.init()
self.number = arc4random()
}
func == (lhs: SomeClass, rhs: SomeClass) -> Bool
{
return true
}
func < (lhs: SomeClass, rhs: SomeClass) -> Bool
{
return true
}
}
You see this error, because operators have to be overloaded outside the class definition, e.g. move
func == (lhs: SomeClass, rhs: SomeClass) -> Bool
{
return true
}
func < (lhs: SomeClass, rhs: SomeClass) -> Bool
{
return true
}
outside your class definition and it will work (except for that they do not return the proper result with this implementation).