I added an extension for the UnsignedInteger protocol to add a hex method that represents the number in hex format. I also want for specific conforming structs to have default value for a parameter. What I wrote is the below.
extension UnsignedInteger {
func hex(withFieldWidth fieldWidth: Int, andUseUppercase uppercase: Bool = true) -> String {
return String(format: "%0\(fieldWidth)\(uppercase ? "X" : "x")", self as! CVarArg)
}
}
extension UnsignedInteger where Self == UInt8 {
func hex(withFieldWidth fieldWidth: Int = 2, andUseUppercase uppercase: Bool = true) -> String {
// should call the UnsignedInteger implementation with the default parameters
return hex(withFieldWidth: fieldWidth, andUseUppercase: uppercase)
}
}
extension UnsignedInteger where Self == UInt16 {
func hex(withFieldWidth fieldWidth: Int = 4, andUseUppercase uppercase: Bool = true) -> String {
// should call the UnsignedInteger implementation with the default parameters
return hex(withFieldWidth: fieldWidth, andUseUppercase: uppercase)
}
}
However, for the UInt8 and UInt16 specific extensions, it seems to be calling itself and not the hex from the first extension block, as explained by the warning message I get for the UInt8 and UInt16 blocks: All paths through this function will call itself
.
If I remove the fieldWidh
from the UInt8 and UInt16 blocks, calling hex (with hardcoded values for fieldWidth
) seems to compile fine, I believe this way it is calling the hex method from the first extension block. Below is the code that compiles fine.
extension UnsignedInteger {
func hex(withFieldWidth fieldWidth: Int, andUseUppercase uppercase: Bool = true) -> String {
return String(format: "%0\(fieldWidth)\(uppercase ? "X" : "x")", self as! CVarArg)
}
}
extension UnsignedInteger where Self == UInt8 {
func hex(andUseUppercase uppercase: Bool = true) -> String {
// should call the UnsignedInteger implementation with the default parameters
return hex(withFieldWidth: 2, andUseUppercase: uppercase)
}
}
extension UnsignedInteger where Self == UInt16 {
func hex(andUseUppercase uppercase: Bool = true) -> String {
// should call the UnsignedInteger implementation with the default parameters
return hex(withFieldWidth: 4, andUseUppercase: uppercase)
}
}
Is there a way to specify a default value for the parameter for specific conforming structs when doing a protocol extension?
Is there a way to specify a default value for the parameter for specific conforming structs when doing a protocol extension?
You have highlighted the problems with this approach in the question already.
How can I solve it in a different way?
UnsignedInteger
inherits fromBinaryInteger
that can provide youbitWidth
information (UInt8
=>8
,UInt16
=>16
and so on).
extension UnsignedInteger {
func hex(uppercase: Bool = true) -> String {
let fieldWidth = self.bitWidth / 4
return String(format: "%0\(fieldWidth)\(uppercase ? "X" : "x")", self as! CVarArg)
}
}
Above makes it work for UInt
, UInt8
, UInt16
, UInt32
& UInt64
.
Taking it one step further, you can do this with FixedWidthInteger
& now it will work for all signed and unsigned integers.