Swift's pow() function won't accept Doubles as arguments

downcast, generics, pow, swift, type-constraints

Solution

why is it complaining about this?

Because pow returns `Double`. And `Double` is not identical to `T`. The error message is misleading, but it means "Cannot find `pow` that accepts `(Double, Double)` and returns `T` type"

I think you are misunderstanding "cast" in Swift. In Swift `as` does not convert numeric types.

let intVal:Int = 12
let doubleVal:Double = intVal as Double
//                            ^ [!] error: 'Int' is not convertible to 'Double'

And If the type of operand is not predictable at compile time, invalid casting causes runtime error:

func foo<T: IntegerLiteralConvertible>(x: T)  {
    x as Double // <-- Execution was interrupted
}
foo(12 as Int)

Instead, we must explicitly "convert" them. see the document: Numeric Type Conversion

let intVal:Int = 12
let doubleVal:Double = Double(intVal)

This works only because `Double` has `init(_ v: Int)` initializer. The following code does not compile:

func foo<T: IntegerLiteralConvertible>(x: T)  {
    Double(x)
//  ^~~~~~~~~ [!] error: cannot invoke 'init' with an argument of type 'T'
}

Because `Double` does not have `init<T:IntegerLiteralConvertible>(_ val:T)` initializer.

So, if you want to use `pow()`, you must convert `T` to `Double` for arguments, and convert `Double` to `T` for returning value. And there is no simple solution for that.

Problem

I created this `infix operator ^^` as a substitute to using the `pow` function: ``` infix operator ^^ { associativity left precedence 155 } func ^^ <T: IntegerLiteralConvertible>(left: T, right: T) -> T { return pow(left as Double, right as Double) } ``` I used the `IntegerLiteralConvertible` protocol as a type constraint for the generics `left` and `right`, because from my understanding this diagramm shows, that it basically includes all number types. In order to use the `pow` function I have to downcast `left` and `right` to `Double` though, which I did using the `as` operator. It's not the safest approach, but that's besides the point. When implementing the function this way swift tells me: ``` <stdin>:4:12: error: cannot invoke 'pow' with an argument list of type '(Double, Double)' return pow(left as Double, right as Double) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` Now as far as I know `pow` takes two `Double`s as parameters, so why is it complaining about this?

Original source