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)
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.
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
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
Let's say I have this extension for CGFloat
extension CGFloat {
// common
public var thrice: CGFloat { return self * 3.0 }
public var twice: CGFloat { return self * 2.0 }
public var half: CGFloat { return self * 0.5 }
public var third: CGFloat { return self / 3.0 }
public var fourth: CGFloat { return self * 0.25 }
public var sixth: CGFloat { return self / 6.0 }
public var eighth: CGFloat { return self * 0.125 }
public var twelfth: CGFloat { return self / 12.0 }
public var sixteenth: CGFloat { return self * 0.0625 }
//
public var inverse: CGFloat { return 1.0 / self }
}
What I want to do is have these apply to CGFloat, Double and Float without having to copy/paste the code. Is this at all possible?
Thanks!
You cannot do it by extending the types (all at once), but you could do it using templated functions:
protocol FloatLiteralMultipliable: FloatLiteralConvertible {
func *(lhs: Self, rhs: Self) -> Self
func /(lhs: Self, rhs: Self) -> Self
}
extension Float: FloatLiteralMultipliable {}
extension CGFloat: FloatLiteralMultipliable {}
extension Double: FloatLiteralMultipliable {}
func thrice<T: FloatLiteralMultipliable>(value: T) -> T { return value * 3.0 }
func twice<T: FloatLiteralMultipliable>(value: T) -> T { return value * 2.0 }
func half<T: FloatLiteralMultipliable>(value: T) -> T { return value / 2.0 }
func third<T: FloatLiteralMultipliable>(value: T) -> T { return value / 3.0 }
func fourth<T: FloatLiteralMultipliable>(value: T) -> T { return value / 4.0 }
func sixth<T: FloatLiteralMultipliable>(value: T) -> T { return value / 6.0 }
func eighth<T: FloatLiteralMultipliable>(value: T) -> T { return value * 0.125 }
func twelfth<T: FloatLiteralMultipliable>(value: T) -> T { return value / 12.0 }
func sixteenth<T: FloatLiteralMultipliable>(value: T) -> T { return value / 0.0625 }
func inverse<T: FloatLiteralMultipliable>(value: T) -> T { return 1.0 / value }
thrice(Float(10.0)) // 30.0
half(CGFloat(2)) // 1.0
inverse(Double(1.0/10.0)) // 10.0
Note: I am only explicitly constructing the types in my example calls to prove that it the functions can be used with each of the types