So I have a method that has 3 different types of arguments that could come in:
Int32
, Int
and Double
. So the idea was to use generics to minimize the interface
func resetProgressBarChunks<T:Numeric>(originalIterationCount: T) {
guard let iCount = originalIterationCount as? Double else {return}
But what I have realized, is at runtime, the Int32
and Int
arguments will actually fail that guard let
. It makes sense, it was just wishful thinking on my part.
But if I try to simply cast a Numeric
into a double, the compiler will bark:
func resetProgressBarChunks<T:Numeric>(originalIterationCount: T) {
guard let iCount = Double(originalIterationCount) else {return}
Cannot invoke initializer for type 'Double' with an argument of type '(T)'
Which I suppose also makes sense, because there is no initializer for Double that takes a Generic.
So it looks like I'm about to be forced to write 3 methods with different parameter types. The Int32
and Int
parameter types would just cast into a Double
and then call the Double
method. Is this really the best way? I really was hoping I could leverage Numeric
somehow
... because there is no initializer for Double that takes a Generic.
That is not entirely true. There is no initializer taking a Numeric
argument. But there are generic initializers taking BinaryInteger
and BinaryFloatingPoint
arguments, so that two overloads are sufficient:
func resetProgressBarChunks<T: BinaryInteger>(originalIterationCount: T) {
let iCount = Double(originalIterationCount)
// ...
}
func resetProgressBarChunks<T: BinaryFloatingPoint>(originalIterationCount: T) {
let iCount = Double(originalIterationCount)
// ...
}
This covers Double
, Int
, Int32
arguments as well as Float
and all other fixed-size integer types.
Just for purposes of syntactical illustration, here's an example of making this a generic and arriving at a Double for all three types:
func f<T:Numeric>(_ i: T) {
var d = 0.0
switch i {
case let ii as Int:
d = Double(ii)
case let ii as Int32:
d = Double(ii)
case let ii as Double:
d = ii
default:
fatalError("oops")
}
print(d)
}
But whether this is better than overloading is a matter of opinion. In my view, overloading is far better, because with the generic we are letting a bunch of unwanted types in the door. The Numeric contract is a lie. A triple set of overloads for Double, Int, and Int32 would turn the compiler into a source of truth.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With