5

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!

JP.
  • 544
  • 5
  • 20

1 Answers1

9

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

drewag
  • 93,393
  • 28
  • 139
  • 128
  • Isn't it better to just extend `integertype`? Also how can they relate to the extenstion when they are after the `{}` – mfaani Sep 08 '16 at 11:29
  • playgrounds is not letting this compile ... any suggestions or update .. gives warning warning: 'FloatLiteralConvertible' is deprecated: renamed to 'ExpressibleByFloatLiteral' but if i change type to new name still doesn't compile – lozflan Aug 15 '17 at 22:17