New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SR-3970] Rework ExpressibleBy(Integer|Float)Literal protocols #46555
Comments
Ok, I might really not be the best person to tackle this problem, but here we go:
public protocol ExpressibleByIntegerLiteral {
init(integerLiteral value: Int32)
init(sign: FloatingPointSign, significands: [UInt16])
}
extension ExpressibleByIntegerLiteral {
init(sign: FloatingPointSign, significands: [UInt16]) {
precondition(significands.count == 1, "Type does not support big numbers")
let signFactor: Int32 = sign == .minus ? -1 : 1
self.init(integerLiteral: signFactor * Int32(significands[0]))
}
}
public protocol ExpressibleByFloatLiteral : ExpressibleByIntegerLiteral {
init(floatLiteral value: Double)
init(sign: FloatingPointSign, exponent: Int, significand: Int)
}
extension ExpressibleByFloatLiteral {
init(sign: FloatingPointSign, exponent: Int, significand: Int) {
self.init(floatLiteral: Double(
sign: sign,
exponent: exponent,
significand: Double(significand)))
}
}
Here's the big picture:
integer = (sign == .minus ? -1 : 1) * (x0 + x1*radix + x2*radix^2 + x3*radix^3 + ...
|
The `init(sign:significands)` approach seems totally reasonable to me; I'd suggest doing roughly the same thing with the `ExpressibleByFloatLiteral` initializer, so we allow arbitrary-precision floats. I do wonder if it's better to just pass an unsafe buffer pointer, because arrays are a bit heavyweight for this part of the system. Was your intent for the `init(floatLiteral🙂` and `init(integerLiteral🙂` initializers to be there for backward compatibility, or something else? I think the associated types could go away; they're there so we can do a hack with the builtin types that the Swift compiler recognizes. |
> I think the associated types could go away; they're there so we can do a hack with the builtin types that the Swift compiler recognizes. If they go away, we have to decide on what type init(integerLiteral value: Int) takes as argument. The logic would dictate to go with Int64 so as to support 64bit integer literals. But then, a conforming type that doesn't support 64bit ints would have to resort to a runtime crash to signify it doesn't support them. Example: enum CSSValue {
case pixel(Int32)
case percent(Int32)
}
extension CSSValue : ExpressibleByIntegerLiteral {
init(integerLiteral value: Int64) {
self = .pixel(Int(value))
}
} Whereas, right now, we can generate a compile time error: extension CSSValue : ExpressibleByIntegerLiteral {
init(integerLiteral value: Int32) {
self = .pixel(value)
}
}
let value: CSSValue = 9_223_372_036_854_775_807
// error: integer literal '9223372036854775807' overflows when stored into 'Int32' > Was your intent for the `init(floatLiteral` and `init(integerLiteral` initializers to be there for backward compatibility, or something else? No, the reasoning was for them to stay for when a conforming type does not require arbitrary precision and wants to implement a simple initializer, hence the default implementations of the arbitrary precision initialiser containing a precondition for significands.count == 1. But we could transform that into a compile time error: public protocol ExpressibleByIntegerLiteral {
init(integerLiteral value: Int64)
}
public protocol ExpressibleByArbitraryPrecisionIntegerLiteral {
init(sign: FloatingPointSign, buffer: UnsafeBufferPointer<Int64>)
} The compiler would then generate an error when trying to assign an integer literal greater than Int64.max into a type that conforms to ExpressibleByIntegerLiteral but not ExpressibleByArbitraryPrecisionIntegerLiteral. Thoughts? |
@swift-ci create |
Let's track this as part of SR-920. |
Additional Detail from JIRA
md5: 6995ebdcce03aa3a38889089bb6d4141
duplicates:
relates to:
Issue Description:
The ExpressibleByIntegerLiteral and ExpressibleByFloatLiteral protocols have a number of problems that should be addressed by a redesign:
They don't support arbitrary-precision integer/floating point, so (for example) you cannot create a properly-working BigNum type that conforms to ExpressibleByIntegerLiteral. We need a better way to provide the raw integer values.
Their fallback to "builtin" types is weird and doesn't make sense; the _Builtin versions of these protocols shouldn't be needed
It probably makes sense for ExpressibleByFloatLiteral to inherit ExpressibleByIntegerLiteral
The text was updated successfully, but these errors were encountered: