Swift: calculating atan2(y,x) for FloatingPoint numbers? - swift

If the only thing I know about the variables x, y is that they are of type T which is conforming to the FloatingPoint protocol, how can I calculate the value of atan2(y, x) and return it as an instance of type T?
Actually, I was trying to implement a Vector2D protocol, but I met problems with the following methods/properties:
.init(radius r:Component, angle a:Component)
.angle
The following is my implementation:
/*
Swift Tip: Vector Algebra with Protocols
https://www.objc.io/blog/2018/11/29/vector-calculus-with-protocols/
FloatingPoint
https://developer.apple.com/documentation/swift/floatingpoint
*/
import Foundation // cos, sin
// math constants
extension FloatingPoint {
public static var deg: Self { .pi / 180 }
}
/// Vector2D
public protocol Vector2D: ExpressibleByArrayLiteral, CustomStringConvertible {
// vector component type
associatedtype Component: FloatingPoint
// (x,y) coordinates
var x: Component { get }
var y: Component { get }
// required initializer
init(x: Component, y: Component)
}
// custom operators (declaration)
// ⭐️ can only be declared at file scope
infix operator • : MultiplicationPrecedence // inner product
infix operator × : MultiplicationPrecedence // outer product
// ExpressibleByArrayLiteral
public extension Vector2D {
public init(arrayLiteral a: Component...) {
assert(a.count >= 2, "Must initialize vector with at least 2 values.")
self.init(x: a[0], y: a[1])
}
}
// CustomStringConvertible
public extension Vector2D {
public var description: String { "(\(x), \(y))" }
}
// initializers & factory methods
public extension Vector2D {
// usage: Self(x, y)
public init(_ x:Component, _ y:Component) {
self.init(x: x, y: y)
}
// usage: Self(radius: r, angle: a)
public init(radius r:Component, angle a:Component) {
let r = r as! Double // ⛔️doesn't work‼️
let a = a as! Double
let x = r * cos(a) as! Component
let y = r * sin(a) as! Component
self.init(x: x, y: y)
}
// usage: Self.polar(r, a)
public static func polar(_ r: Component, _ a: Component) -> Self {
Self(radius: r, angle: a)
}
}
// constant vectors
public extension Vector2D {
// zero vector: (0,0)
public static var zero: Self {
Self(x: Component.zero, y: Component.zero)
}
}
// vector operations
public extension Vector2D {
// u + v
public static func + (u: Self, v: Self) -> Self {
Self(x: u.x + v.x, y: u.y + v.y)
}
// -u (prefix)
public static prefix func - (v: Self) -> Self {
Self(x: -v.x, y: -v.y)
}
// u - v
public static func - (u: Self, v: Self) -> Self {
u + (-v)
}
// a * v, v * a, v / a (scalar product)
public static func * (a: Component, v: Self) -> Self {
Self(x:a * v.x, y: a * v.y)
}
public static func * (v: Self, a: Component) -> Self {
a * v
}
public static func / (v: Self, a: Component) -> Self {
(1/a) * v
}
// u • v (dot product)
public static func • (u: Self, v: Self) -> Component {
u.x * v.x + u.y * v.y // x1x2 + y1y2
}
// u × v (cross product)
public static func × (u: Self, v: Self) -> Component {
u.x * v.y - u.y * v.x // ad - bc
}
}
// complex numbers
public extension Vector2D {
// z1 * z2 (complex product)
public static func * (z1: Self, z2: Self) -> Self {
let (a,b) = (z1.x, z1.y) // z1 = a + bi
let (c,d) = (z2.x, z2.y) // z2 = c + di
return Self(x: a*c - b*d, y: a*d + b*c) // z1 * z2 = (ac-bd) + (ad+bc)i
}
// z.conjugate
public var conjugate: Self { Self(x: x, y: -y) } // a - bi
// z1 / z2 (complex division)
public static func / (z1: Self, z2: Self) -> Self {
z1 * z2.conjugate / (z2 • z2)
}
}
// vector properties
public extension Vector2D {
public var length: Component { sqrt(self • self) } // |v|
public var magnitude: Component { length } // |v|
public var angle: Component { // in radians
atan2(y as! Double, x as! Double) as! Component // ⛔️doesn't work‼️
}
public var degrees: Component { angle / .deg } // in degrees
}

My workaround: (including 2 files - Vector2D.swift and CGPoint+Vector2D.swift)
Vector2D.swift
import Foundation
// math constants
extension FloatingPoint {
public static var deg: Self { .pi / 180 }
}
// protocol for Vector2D.Component
public protocol VectorComponent: FloatingPoint {
static func cos(_ x: Self) -> Self
static func sin(_ x: Self) -> Self
static func atan2(_ y: Self, _ x: Self) -> Self
}
/// Vector2D
public protocol Vector2D: ExpressibleByArrayLiteral, CustomStringConvertible {
// vector component type
associatedtype Component: VectorComponent
// (x,y) coordinates
var x: Component { get }
var y: Component { get }
// required initializer
init(x: Component, y: Component)
}
// custom operators (declaration)
// ⭐️ can only be declared at file scope
infix operator • : MultiplicationPrecedence // inner product
infix operator × : MultiplicationPrecedence // outer product
// ExpressibleByArrayLiteral
public extension Vector2D {
public init(arrayLiteral elements: Component...) {
let a = elements + [0, 0] // make sure that a.count >= 2
self.init(x: a[0], y: a[1])
}
}
// CustomStringConvertible
public extension Vector2D {
public var description: String { "(\(x), \(y))" }
}
// initializers & factory methods
public extension Vector2D {
// usage: Self(x, y)
public init(_ x:Component, _ y:Component) {
self.init(x: x, y: y)
}
// usage: Self(radius: r, angle: a)
public init(radius r: Component, angle a: Component) {
self.init(x: r * Component.cos(a), y: r * Component.sin(a))
}
// usage: Self.polar(r, a)
public static func polar(_ r: Component, _ a: Component) -> Self {
Self(radius: r, angle: a)
}
}
// constant vectors
public extension Vector2D {
// zero vector: (0,0)
public static var zero: Self {
Self(x: Component.zero, y: Component.zero)
}
}
// vector operations
public extension Vector2D {
// u + v
public static func + (u: Self, v: Self) -> Self {
Self(x: u.x + v.x, y: u.y + v.y)
}
// -u (prefix)
public static prefix func - (v: Self) -> Self {
Self(x: -v.x, y: -v.y)
}
// u - v
public static func - (u: Self, v: Self) -> Self {
u + (-v)
}
// a * v, v * a, v / a (scalar product)
public static func * (a: Component, v: Self) -> Self {
Self(x:a * v.x, y: a * v.y)
}
public static func * (v: Self, a: Component) -> Self {
a * v
}
public static func / (v: Self, a: Component) -> Self {
(1/a) * v
}
// u • v (dot product)
public static func • (u: Self, v: Self) -> Component {
u.x * v.x + u.y * v.y // x1x2 + y1y2
}
// u × v (cross product)
public static func × (u: Self, v: Self) -> Component {
u.x * v.y - u.y * v.x // ad - bc
}
}
// complex numbers
public extension Vector2D {
// z1 * z2 (complex product)
public static func * (z1: Self, z2: Self) -> Self {
let (a,b) = (z1.x, z1.y) // z1 = a + bi
let (c,d) = (z2.x, z2.y) // z2 = c + di
return Self(x: a*c - b*d, y: a*d + b*c) // z1 * z2 = (ac-bd) + (ad+bc)i
}
// z.conjugate
public var conjugate: Self { Self(x: x, y: -y) } // a - bi
// z1 / z2 (complex division)
public static func / (z1: Self, z2: Self) -> Self {
z1 * z2.conjugate / (z2 • z2)
}
}
// vector properties
public extension Vector2D {
public var length: Component { sqrt(self • self) } // |v|
public var magnitude: Component { length } // |v|
public var angle: Component { Component.atan2(y, x) } // in radians
public var degrees: Component { angle / .deg } // in degrees
}
// vector functions
public func abs<T: Vector2D>(_ v: T) -> T.Component {
v.length
}
CGPoint+Vector2D.swift
import CoreGraphics // for CGPoint, cos, sin, atan2
// CGFloat (protocol conformance)
extension CGFloat: VectorComponent {
public static func cos(_ x: CGFloat) -> CGFloat { CoreGraphics.cos(x) }
public static func sin(_ x: CGFloat) -> CGFloat { CoreGraphics.sin(x) }
public static func atan2(_ y: CGFloat, _ x: CGFloat) -> CGFloat { CoreGraphics.atan2(y,x) }
}
// CGPoint (protocol conformance)
extension CGPoint: Vector2D {}

Related

How can I define ShapeBuilder for SwiftUI

As we know we have a very useful wrapper called #ViewBuilder for view but I am missing same wrapper for Shape protocol, Since there is no wrapper for this available, I am looking to try build one for learning porous.
Here is working code for view and looking to build the wrapper for Shape:
#ViewBuilder func testForView(value: Bool) -> some View {
if value {
Text("Hello")
}
else {
Button("world!") {}
}
}
// The Goal:
#ShapeBuilder func testForShape(value: Bool) -> some Shape {
if value {
Circle()
}
else {
Rectangle()
}
}
I have experience working with wrappers or even defining a custom wrapper, but all my attempts were wrapping a value, not a function! I never tried to wrapp a function, frankly I do not know that it is thing in Swift or SwiftUI. So how can I make #ShapeBuilder works like #ViewBuilder works, I know that I must use Tuple or more correctly TupleShape, so I think I should define TupleShape as well.
First we should ask whether it's worth writing a ShapeBuilder instead of writing an AnyShape type like this:
public struct AnyShape: Shape {
public let makePath: (CGRect) -> Path
public init(makePath: #escaping (CGRect) -> Path) {
self.makePath = makePath
}
public init<Wrapped: Shape>(_ shape: Wrapped) {
self.makePath = { shape.path(in: $0) }
}
public func path(in rect: CGRect) -> Path {
return makePath(rect)
}
}
We can use AnyShape to write your testForShape function like this:
func testForShape(value: Bool) -> AnyShape {
if value {
return AnyShape(Circle())
}
else {
return AnyShape(Rectangle())
}
}
I've used AnyShape in various projects.
Anyway, if we want to write ShapeBuilder, we can start with the simplest possible implementation, which only supports a body containing a single, unconditional child shape:
#resultBuilder
public struct ShapeBuilder {
public static func buildBlock<C0: Shape>(_ c0: C0) -> C0 { c0 }
}
We can now use it like this:
#ShapeBuilder
func shape1() -> some Shape {
Circle()
}
Hooray!
We can extend it to support a body containing no child shapes by adding a zero-argument buildBlock and an EmptyShape type for it to return:
extension ShapeBuilder {
public static func buildBlock() -> EmptyShape { EmptyShape() }
}
public struct EmptyShape: Shape {
public func path(in rect: CGRect) -> Path { Path() }
}
Now we can write the following function without errors:
#ShapeBuilder
func shape0() -> some Shape {
}
To support an if statement without an else clause, we add a buildOptional method and an OptionalShape type for it to return:
extension ShapeBuilder {
public static func buildOptional<C0: Shape>(_ c0: C0?) -> OptionalShape<C0> {
return OptionalShape(c0)
}
}
public struct OptionalShape<Content: Shape>: Shape {
public let content: Content?
public init(_ content: Content?) {
self.content = content
}
public func path(in rect: CGRect) -> Path {
return content?.path(in: rect) ?? Path()
}
}
Now we can use it like this:
#ShapeBuilder
func shape2(flag: Bool) -> some Shape {
if flag {
Circle()
}
}
To support an if statement with an else clause, and to support a switch statement, we add buildEither and an EitherShape type for it to return:
extension ShapeBuilder {
public static func buildEither<First: Shape, Second: Shape>(first: First) -> EitherShape<First, Second> {
return .first(first)
}
public static func buildEither<First: Shape, Second: Shape>(second: Second) -> EitherShape<First, Second> {
return .second(second)
}
}
public enum EitherShape<First: Shape, Second: Shape>: Shape {
case first(First)
case second(Second)
public func path(in rect: CGRect) -> Path {
switch self {
case .first(let first): return first.path(in: rect)
case .second(let second): return second.path(in: rect)
}
}
}
We can now write this function:
#ShapeBuilder
func shape3(_ n: Int) -> some Shape {
if n < 0 {
Rectangle()
} else {
switch n {
case 0:
EmptyShape()
case 1:
Rectangle()
default:
Capsule()
}
}
}
We can support combining two child shapes by writing a buildBlock method that takes two arguments, and a Tuple2Shape for it to return:
extension ShapeBuilder {
public static func buildBlock<C0: Shape, C1: Shape>(_ c0: C0, _ c1: C1) -> Tuple2Shape<C0, C1> {
return Tuple2Shape(c0, c1)
}
}
public struct Tuple2Shape<C0: Shape, C1: Shape>: Shape {
public let tuple: (C0, C1)
public init(_ c0: C0, _ c1: C1) {
tuple = (c0, c1)
}
public func path(in rect: CGRect) -> Path {
var path = tuple.0.path(in: rect)
path.addPath(tuple.1.path(in: rect))
return path
}
}
Now we can write this function:
#ShapeBuilder
func shape4() -> some Shape {
Circle()
Rectangle()
}
We can support combining two child shapes by writing a buildBlock method that takes three arguments, and a Tuple3Shape for it to return:
extension ShapeBuilder {
public static func buildBlock<C0: Shape, C1: Shape, C2: Shape>(_ c0: C0, _ c1: C1, _ c2: C2) -> Tuple3Shape<C0, C1, C2> {
return Tuple3Shape(c0, c1, c2)
}
}
public struct Tuple3Shape<C0: Shape, C1: Shape, C2: Shape>: Shape {
public let tuple: (C0, C1, C2)
public init(_ c0: C0, _ c1: C1, _ c2: C2) {
tuple = (c0, c1, c2)
}
public func path(in rect: CGRect) -> Path {
var path = tuple.0.path(in: rect)
path.addPath(tuple.1.path(in: rect))
path.addPath(tuple.2.path(in: rect))
return path
}
}
That lets us write this function:
#ShapeBuilder
func shape5() -> some Shape {
Circle()
Rectangle()
Capsule()
}
ViewBuilder has buildBlock methods up to arity 10, but I'm not going to write out any more. You can do it yourself if you need them.
Anyway, here's the ShapeBuilder implementation all together for easy copy'n'paste:
#resultBuilder
public struct ShapeBuilder {
public static func buildBlock<C0: Shape>(_ c0: C0) -> C0 { c0 }
}
extension ShapeBuilder {
public static func buildBlock() -> EmptyShape { EmptyShape() }
}
public struct EmptyShape: Shape {
public func path(in rect: CGRect) -> Path { Path() }
}
extension ShapeBuilder {
public static func buildOptional<C0: Shape>(_ c0: C0?) -> OptionalShape<C0> {
return OptionalShape(c0)
}
}
public struct OptionalShape<Content: Shape>: Shape {
public let content: Content?
public init(_ content: Content?) {
self.content = content
}
public func path(in rect: CGRect) -> Path {
return content?.path(in: rect) ?? Path()
}
}
extension ShapeBuilder {
public static func buildEither<First: Shape, Second: Shape>(first: First) -> EitherShape<First, Second> {
return .first(first)
}
public static func buildEither<First: Shape, Second: Shape>(second: Second) -> EitherShape<First, Second> {
return .second(second)
}
}
public enum EitherShape<First: Shape, Second: Shape>: Shape {
case first(First)
case second(Second)
public func path(in rect: CGRect) -> Path {
switch self {
case .first(let first): return first.path(in: rect)
case .second(let second): return second.path(in: rect)
}
}
}
extension ShapeBuilder {
public static func buildBlock<C0: Shape, C1: Shape>(_ c0: C0, _ c1: C1) -> Tuple2Shape<C0, C1> {
return Tuple2Shape(c0, c1)
}
}
public struct Tuple2Shape<C0: Shape, C1: Shape>: Shape {
public let tuple: (C0, C1)
public init(_ c0: C0, _ c1: C1) {
tuple = (c0, c1)
}
public func path(in rect: CGRect) -> Path {
var path = tuple.0.path(in: rect)
path.addPath(tuple.1.path(in: rect))
return path
}
}
extension ShapeBuilder {
public static func buildBlock<C0: Shape, C1: Shape, C2: Shape>(_ c0: C0, _ c1: C1, _ c2: C2) -> Tuple3Shape<C0, C1, C2> {
return Tuple3Shape(c0, c1, c2)
}
}
public struct Tuple3Shape<C0: Shape, C1: Shape, C2: Shape>: Shape {
public let tuple: (C0, C1, C2)
public init(_ c0: C0, _ c1: C1, _ c2: C2) {
tuple = (c0, c1, c2)
}
public func path(in rect: CGRect) -> Path {
var path = tuple.0.path(in: rect)
path.addPath(tuple.1.path(in: rect))
path.addPath(tuple.2.path(in: rect))
return path
}
}

In Swift, how do I add a setter to immutable GLKit vector structs?

In Swift GLKit vectors are immutable structs:
public struct _GLKVector2 {
public var v: (Float, Float)
public init(v: (Float, Float))
public init()
}
extension GLKVector2 {
public var x: Float { get }
public var y: Float { get }
public var s: Float { get }
public var t: Float { get }
public subscript(i: Int) -> Float { get }
}
public typealias GLKVector2 = _GLKVector2
I find this a bit restrictive and would like to extend GLKVector2 to include corresponding setters. How do I do this?
You could create a mutating func that replaces the whole self.
extension GLKVector2 {
mutating func setX(_ x: Float) {
self = GLKVector2Make(x, y)
}
}
...
v2.setX(123)
You could create a property as well, but be careful you will need to write your own getter as well, and you can't return self.x there.
var x: Float {
get {
return v.0
// Note:
// 1. you need to use a getter
// 2. you cannot `return x`, otherwise it will be an infinite recursion
}
set {
self = GLKVector2Make(newValue, y)
}
}

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

Swift 2.0 Set not working as expected when containing NSObject subclass

After upgrading our codebase to Swift2 I've encountered unusual problem. Set is not substracting nor unioning as expected.
class A: NSObject {
let h: Int
init(h: Int) {
self.h = h
}
override var hashValue: Int {
return h
}
}
func ==(lhs: A, rhs: A) -> Bool {
return lhs.hashValue == rhs.hashValue
}
let a = A(h: 1)
let b = A(h: 1)
var sa = Set([a])
let sb = Set([b])
sa.subtract(sb).count // Swift1.2 prints 0, Swift 2 prints 1
sa.contains(a) // Swift1.2 true, Swift 2 true
sa.contains(b) // Swift1.2 true, Swift 2 false
It looks like new Set is not using hashValue for internal operations. Any idea is that a bug, or a way to workaround this issue?
I played with your code a bit. I was able to get it working by no longer subclassing NSObject, but instead conforming to the Hashable protocol:
class A: Hashable {
let h: Int
init(h: Int) {
self.h = h
}
var hashValue: Int {
return h
}
}
func ==(lhs: A, rhs: A) -> Bool {
return lhs.hashValue == rhs.hashValue
}
let a = A(h: 1)
let b = A(h: 1)
var sa = Set([a])
let sb = Set([b])
sa.subtract(sb).count // Swift1.2 prints 0, Swift 2 prints 1
sa.contains(a) // Swift1.2 true, Swift 2 true
sa.contains(b) // Swift1.2 true, Swift 2 false
a.hashValue == b.hashValue
When you were inheriting from NSObject, your == overload wasn't actually being executed. If you want this to work with NSObject, you'd have to override isEquals:
override func isEqual(object: AnyObject?) -> Bool {
if let object = object as? A {
return object.h == self.h
} else {
return false
}
}
//: Playground - noun: a place where people can play
import Foundation
class X: NSObject {
var x:String
var y:Int
init(x:String, y:Int) {
self.x = x
self.y = y
super.init()
}
override var hashValue: Int {
return x.hashValue ^ y.hashValue
}
override func isEqual(object: AnyObject?) -> Bool {
if let rhs = object as? X {
return x == rhs.x && y == rhs.y
} else {
return false
}
}
}
func == (lhs:X, rhs:X) -> Bool {
return lhs.isEqual(rhs)
}
let x = X(x: "x1", y: 1)
let y = X(x: "x1", y: 1)
X(x: "x1", y: 1) == X(x: "x1", y: 1) // Swift 'x == y' (true)
x.isEqual(y) // Obj-C '[x isEqual: y]' (true)
var s:Set<X> = [X(x: "x1", y: 1)]
s.count // count == 1
s.insert(X(x: "x2", y: 1))
s.count // count == 2
s.insert(X(x: "x1", y: 1))
s.count // count == 2
s.insert(X(x: "x2", y: 1))
s.count // count == 2
I spent time looking for the right answer to this until I hit this Question/Answer. I had reverted to basics in XCode Playground to see what was happening. Using subclasses of NSObject in Swift Set makes a bunch of more readable code.

Can I apply the same extension to many classes without copy paste?

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