swift-numberkit
swift-numberkit copied to clipboard
Type 'UInt64' does not conform to protocol 'IntegerNumber'
I'm getting error in my xcode project when I have used the latest version of Hedera SDK Swift so I checked it uses the latest version of NumberKit library which causing this issue.
This is related to a bug fix I did recently, which apparently has lead to a similar bug being introduced in the Hedera SDK (probably long ago). NumberKit used to contain the following code:
extension UInt64: IntegerNumber {
public var doubleValue: Double {
return Double(self)
}
}
This is semantically incorrect, because IntegerNumber is representing signed integers (and uses the corresponding Swift protocols). Unfortunately, the Swift compiler wasn't able to detect this broken protocol compliance so far and the erroneous code was not noticed. With Swift 6 (which is the default soon), this broken compliance will be reported as a warning and my guess is that eventually, this will become an error.
Unfortunately, the Swift Hedera API contains a similar erroneous definition when extending Rational (these are signed rational numbers — see the comment in the NumberKit implementation of Rational):
extension Rational: ProtobufCodable where T == UInt64 {
internal typealias Protobuf = Proto_Fraction
internal init(protobuf proto: Protobuf) {
self.init(UInt64(proto.numerator), UInt64(proto.denominator))
}
internal func toProtobuf() -> Protobuf {
.with { proto in
proto.numerator = Int64(self.numerator)
proto.denominator = Int64(self.denominator)
}
}
}
And the fact that the code needs to cast the values multiple times between UInt64 and Int64 shows that negative rationals are guaranteed to crash the application. This is a bug that needs to be fixed in the Hedera API. My guess is that the following change will do the trick, but I have no idea if this is backward compatible:
extension Rational: ProtobufCodable where T == Int64 {
internal typealias Protobuf = Proto_Fraction
internal init(protobuf proto: Protobuf) {
self.init(proto.numerator, proto.denominator)
}
internal func toProtobuf() -> Protobuf {
.with { proto in
proto.numerator = self.numerator
proto.denominator = self.denominator
}
}
}
To silence the error you get for now, there are two options:
- You add the first code snippet of this post to your code/the Swift Hedera API: this is bringing back the broken compliance, but your code compiles. You will get the warning I talked about when switching to Swift 6.
- You replace this line in
Package.swiftof the Swift Hedera API:.package(url: "https://github.com/objecthub/swift-numberkit.git", from: "2.4.1")with.package(url: "https://github.com/objecthub/swift-numberkit.git", exact: "2.5.1"). Everything will work as before, but you won't automatically include further changes toNumberKit.
I'd also be willing to consider changes to NumberKit, e.g. by bringing back the broken protocol compliance if compiled with Swift 5.X. Let me know if this is preferred.