0

I'm creating a custom exponent operator and I tried using a generic type that conforms to the numeric protocol. However, it doesn't work. Numeric seems to be very restrictive about what it supports.

precedencegroup Exponentiative {
  associativity: left
  higherThan: MultiplicationPrecedence
}
infix operator ** : Exponentiative

public func ** <N: Numeric>(base: N, power: N) -> N {
    return N.self( pow(Double(base), Double(power)) )
}

Instead I have to do this:

public func ** <N: BinaryInteger>(base: N, power: N) -> N {
    return N.self( pow(Double(base), Double(power)) )
}
public func ** <N: BinaryFloatingPoint>(base: N, power: N) -> N {
    return N.self( pow(Double(base), Double(power)) )
}

This is fine for short functions, but one could imagine having to write a much longer function than this.

How do I create a generic type that can accept any BinaryInteger or BinaryFloatingPoint?

I there any way to combine these functions into just one? This code duplication seems unnecessary.


This post is NOT a duplicate of Is there a way to convert any generic Numeric into a Double?

The first answer, when applied to my problem, would make the function even more redundant:

func f<T:Numeric>(_ i: T) {
    var d: Double

    switch i {
    case let ii as Int:
        d = Double(ii)
    case let ii as Int8:
        d = Double(ii)
    case let ii as UInt8:
        d = Double(ii)
    case let ii as Int16:
        d = Double(ii)
    case let ii as UInt16:
        d = Double(ii)
    case let ii as Int32:
        d = Double(ii)
    case let ii as UInt32:
        d = Double(ii)
    case let ii as Int64:
        d = Double(ii)
    case let ii as UInt64:
        d = Double(ii)

    case let ii as Double:
        d = ii
    case let ii as Float32:
        d = Double(ii)
    case let ii as Float64:
        d = Double(ii)
    case let ii as Float:
        d = Double(ii)


    default:
        fatalError("oops")
    }
    print(d)
}

Also, this switch statement would have to be applied to each argument passed to the function, which means the switch statement would have to be extracted into its own function.

The second answer in the above post is basically the same as the functions in my original post, so it does not answer my question either.

My post has absolutely NOTHING to do with this post: Making my function calculate average of array Swift.

Peter Schorn
  • 916
  • 3
  • 10
  • 20
  • Hey, sorry if you think the duplicate marking was not helpful. It was just a way of saying "This is a well-known fact about Swift numeric types, it has been asked before, and what you are saying you have to do is simply what you have to do." It seemed to me that that was the essence of duplicateness (if that's a word). If you look in the Swift headers, _all_ the numeric functions and operators work this way. That's just how it is. – matt Apr 08 '20 at 12:25
  • @matt Please me more careful next time about marking questions as duplicates. You should only mark a question as a duplicate if it is a duplicate. And if this is a well-known fact about numeric types, than you should've said so in a comment to my question. I'm not sure how marking the question as a duplicate is supposed to communicate that fact to me. I didn't even know that was the case until I read this comment you just posted. – Peter Schorn Apr 08 '20 at 12:52
  • Well, it's a matter of _reading_ the duplicate links. That's the point. Instead of dimissing them, the idea is that you study them and think about them. If you did that, you would discover that the questions and answers at those links deal very completely with what you're talking about here. That's what a duplicate is: isomething that has been asked and answered before. The point is that complaining about this aspect of Swift numerics / generics _again_ adds nothing to the mix; this has been well complained about before. Do you follow? Do not be insulted by a duplicate marking; it's helpul. – matt Apr 08 '20 at 13:22

0 Answers0