ChikabuZ ChikabuZ - 10 months ago 42
Swift Question

Generic half func in Swift

I'm trying to write generic half function for all numeric types:

func half<T where T: FloatingPointType>(value: T) -> T
return value * 0.5

And I see this error:

No '*' candidates produce the expected contextual result type 'T'

Is it possible to write generic function in this case?


Not in Swift 2.2. FloatingPointType is not a very powerful type. In Swift 3 this is possible if you limit yourself to BinaryFloatingPoint (which covers most of the floating point types you're probably thinking of, particularly Float and Double).

func half<T where T: BinaryFloatingPoint>(_ value: T) -> T {
    return value * 0.5

In the most general case of a custom FloatingPointType in Swift 2.2, the system may not have any way to convert this into a Double multiplication and then convert that back into your arbitrary FloatingPointType. The BinaryFloatingPoint protocol adds ExpressibleByFloatLiteral which means that 0.5 can be converted to your arbitrary type.

It's important to keep in mind that the 0.5 in this above code is of type T. It is not a Double. The following code still would not work:

func half<T where T: BinaryFloatingPoint>(_ value: T) -> T {
    let oneHalf = 0.5
    return value * oneHalf 
   // error: binary operator '*' cannot be applied to operands of type 'T' and 'Double'

You cannot multiply two arbitrary floating point numbers. Swift intentionally avoids a lot of automatic type coercion that was a source of subtle bugs in C. In the general case of a custom FloatingPoint, it is not possible to say that one type is "more accurate" than the other. They may have different accuracy over different ranges. And of course you could create a FloatingPoint that is much larger than a double. So there's no obvious "just promote everything to double" rule that you could use.