<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><span></span></div><div><div><br></div><div><br>On 31 Mar 2017, at 10:45, Brent Royal-Gordon <<a href="mailto:brent@architechies.com">brent@architechies.com</a>> wrote:<br><br></div><blockquote type="cite"><div><meta http-equiv="Content-Type" content="text/html charset=utf-8"><div><blockquote type="cite" class=""><div class="">On Mar 30, 2017, at 2:56 PM, David Hart via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);" class="">The current protocols <code style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(27, 31, 35, 0.0470588); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">ExpressibleByIntegerLiteral</code> and <code style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(27, 31, 35, 0.0470588); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">ExpressibleByFloatLiteral</code> 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.</p></div></div></div></blockquote><div>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.</div></div></div></blockquote><div><br></div><div>The two major reason I see is their simplicity and their type safety.</div><div><br></div><div><b>Simplicity</b> </div><div>I recently conformed a type to both protocols and could not support arbitrary precision because the backing type was CGFloat. It would have been less obvious how to implement those conformances with the arbitrary precision initializers. I can easily see another developer be confused by them. For me, they are specialty initializers.</div><div><br></div><div><b>Type-safety</b></div><div>The protocols currently in the Standard Library allow you to implement them using any valid built-in type, providing type-safety: if you try to initialize a conforming type with a literal value outside the bounds of the picked built-in type, you will get a compiler error.</div><br><blockquote type="cite"><div><div><div>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.</div><div><br class=""></div><div>One approach would be to extract the `words` collection into a higher-level protocol:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>protocol BinaryIntegerSource {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>associatedtype Words: Collection where Iterator.Element == UInt</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>var words: Words { get }</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br class=""></div><div>Then we could modify `BinaryInteger` to accept this:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>protocol BinaryInteger: BinaryIntegerSource {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>...</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>init<T : BinaryIntegerSource>(_ source: T)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>...</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br class=""></div><div>And introduce a new `IntegerLiteral` type which is a `BinaryIntegerSource`, but not a `BinaryInteger` (so you can't do arithmetic with it):</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>struct IntegerLiteral: BinaryIntegerSource {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>associatedtype Words = …</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>var words: Words { … }</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br class=""></div><div>And now, you can say something like:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>struct Int128: ExpressibleByIntegerLiteral {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>fileprivate var _value: DoubleWidth<Int64></div><div><span class="Apple-tab-span" style="white-space:pre">                </span></div><div><span class="Apple-tab-span" style="white-space:pre">                </span>init(integerLiteral value: IntegerLiteral) {</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>_value = DoubleWidth(value)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br class=""></div><div>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.</div></div></div></blockquote><div><br></div><div>Looks like a nice solution! It would allow us to keep one ExpressibleBy* protocol.</div><div><br></div><div>Any reason we need to burden ourselves with the two's complement representation?</div><br><blockquote type="cite"><div><div><div>(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.)</div><div><br class=""></div><div>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.</div></div></div></blockquote><div><br></div><div>What do you mean by the universal float conversion?</div><br><blockquote type="cite"><div><div><div>(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`.)</div><div><br class=""></div><div>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.</div></div><div><br class=""></div><div class="">
<span class="Apple-style-span" style="border-collapse: separate; font-variant-ligatures: normal; font-variant-east-asian: normal; font-variant-position: normal; line-height: normal; border-spacing: 0px;"><div class=""><div style="font-size: 12px; " class="">-- </div><div style="font-size: 12px; " class="">Brent Royal-Gordon</div><div style="font-size: 12px; " class="">Architechies</div></div></span>
</div>
<br class=""></div></blockquote></div></body></html>