[swift-evolution] [Discussion] Arbitrary precision integer and float literal protocols
Brent Royal-Gordon
brent at architechies.com
Fri Mar 31 03:45:42 CDT 2017
> On Mar 30, 2017, at 2:56 PM, David Hart via swift-evolution <swift-evolution at swift.org> wrote:
>
> The current protocols ExpressibleByIntegerLiteral and ExpressibleByFloatLiteral are simple and work well but don't support arbitrary precision literal values. Replacing those protocols is a non-goal as they provide a simple interface for work well for most cases.
>
Honestly, I don't think I agree with this. I see no particular reason to like our current protocols; they break down as soon as your type gets larger than the largest standard library integer/float type, which undermines one of their main use cases.
I've been toying with a different approach in my head for a few weeks. The `BinaryInteger` protocol contains the concept of a `words` collection, which expresses any integer type as a collection of `UInt`s containing a signed two's-compliment representation of the integer. That means any `BinaryInteger` already contains code to handle a `words` collection. If we made this more exposed in some way, then `ExpressibleByIntegerLiteral` could leverage that conformance.
One approach would be to extract the `words` collection into a higher-level protocol:
protocol BinaryIntegerSource {
associatedtype Words: Collection where Iterator.Element == UInt
var words: Words { get }
}
Then we could modify `BinaryInteger` to accept this:
protocol BinaryInteger: BinaryIntegerSource {
...
init<T : BinaryIntegerSource>(_ source: T)
...
}
And introduce a new `IntegerLiteral` type which is a `BinaryIntegerSource`, but not a `BinaryInteger` (so you can't do arithmetic with it):
struct IntegerLiteral: BinaryIntegerSource {
associatedtype Words = …
var words: Words { … }
}
And now, you can say something like:
struct Int128: ExpressibleByIntegerLiteral {
fileprivate var _value: DoubleWidth<Int64>
init(integerLiteral value: IntegerLiteral) {
_value = DoubleWidth(value)
}
}
And everything ought to do what it's supposed to. You could still use a different type if you didn't need anything larger than, say, `Int`. I don't believe this would require any changes to the compiler; `IntegerLiteral` could conform to `_ExpressibleByBuiltinIntegerLiteral`, which would allow it to represent integers up to the current limit of 1024 bits + 1 sign bit.
(There are a few similar approaches we could take, like exposing an `init(words:)` constructor in `BinaryInteger` and having the `IntegerLiteral` behave as a `Words` collection, but all of them basically involve bootstrapping into `BinaryInteger` through the `Words` type.)
I *think* that the not-yet-implemented `BinaryFloatingPoint.init<Source: BinaryFloatingPoint>(_ value: Source)` initializers could be leveraged in a similar way—create a `BinaryFloatingPointSource` protocol and a `BinaryFloatLiteral` type that conforms to it—but I'm less certain of that because I don't really understand how this universal float conversion is supposed to work. Plus, the universal float conversion is still just a TODO comment right now.
(This would leave non-binary floats in the lurch, but we're pretty much doing that already—try initializing `Decimal` through its `ExpressibleByFloatLiteral` conformance sometime and you'll see what I mean. I would support changing its name to `ExpressibleByBinaryFloatLiteral`.)
These leave our current integer and floating-point literal size limits (1025-bit signed integers and 80-bit floats) in place, but those are implementation details and could be changed. In practice, I very much hope the compiler will try to optimize initialization from literals aggressively.
--
Brent Royal-Gordon
Architechies
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170331/01763457/attachment.html>
More information about the swift-evolution
mailing list