<div dir="ltr">Great work, all. I&#39;m not sure I ever commented on SE-0104, so I&#39;ve read through this one more carefully. Here are some things that came to mind:<div><div><br></div><div><b>## Arithmetic</b></div><div><br></div><div><div>Why are ExpressibleByIntegerLiteral and init?&lt;T:BinaryInteger&gt;(exactly<wbr>:) required? I could understand needing access to 0, but this could be provided by a static property or nullary initializer. It doesn&#39;t seem like all types supporting arithmetic operations would necessarily be convertible from an arbitrary binary integer.</div></div><div><br></div><div><br></div><div>I tried to evaluate the Arithmetic protocol by considering what it means for higher-dimensional types such as CGPoint and CGVector. My use case was a linear interpolation function:</div><div><br></div><div><font face="monospace, monospace">    func lerp&lt;T: Arithmetic&gt;(from a: T, to b: T, by ratio: T) -&gt; T {</font></div><div><font face="monospace, monospace">        return a + (b - a) * ratio</font></div><div><font face="monospace, monospace">    }</font><br></div><div><br></div><div>If I&#39;ve read the proposal correctly, this definition works for integer and floating-point values. But we can&#39;t make it work properly for CGVector (or, perhaps less mathematically correct but more familiar, CGPoint). It&#39;s okay to define +(CGVector, CGVector) and -(CGVector, CGVector), but *(CGVector, CGVector) and /(CGVector, CGVector) don&#39;t make much sense. What we really want is *(CGVector, <b>CGFloat</b>) and /(CGVector, <b>CGFloat</b>).</div><div><br></div><div>After consulting a mathematician, I believe what the lerp function really wants is for its generic param to be an <a href="https://en.wikipedia.org/wiki/Affine_space" target="_blank">affine space</a>. I explored this a bit here: <a href="https://gist.github.com/jtbandes/93eeb7d5eee8e1a7245387c660d53b03#file-affine-swift-L16-L18" target="_blank">https://gist.github.com/jtband<wbr>es/93eeb7d5eee8e1a7245387c660d<wbr>53b03#file-affine-swift-L16-<wbr>L18</a></div><div><br></div><div>This approach is less restrictive and more composable than the proposed Arithmetic protocol, which can be viewed as a special case with the following definitions:</div><div><br></div><div><font face="monospace, monospace">    extension Arithmetic: AffineSpace, VectorSpace {  // not actually allowed in Swift</font></div><div><font face="monospace, monospace">        typealias Displacement = Self</font></div><div><font face="monospace, monospace">        typealias Scalar = Self</font></div><div><font face="monospace, monospace">    }</font></div><div><br></div><div>It&#39;d be great to be able to define a lerp() which works for all floating-point and integer numbers, as well as points and vectors (assuming a glorious future where CGPoint and CGVector have built-in arithmetic operations). But maybe the complexity of these extra protocols isn&#39;t worth it for the stdlib...</div><div><br></div><div><b><br></b></div><div><b>## BinaryInteger</b></div><div><br></div><div>I&#39;m a little confused by the presence of init(extendingOrTruncating:) for <i>all</i> binary integers. Why does it make sense to be able to write UInt16(extendingOrTruncating: (-21 as Int8)) ? In my mind, sign-extension only has meaning when the source and destination types are both signed.<br></div><div><br></div><div>Although I would not be against a clamp() function in the standard library, &quot;init(clamping:)&quot; sounds strange to me. What about calling it &quot;init(nearestTo:)&quot;?  One could also define a FloatingPoint version of init(nearestTo:), i.e. lround(). For maximum annoyance and explicitness, you could even rename the existing init(_:) to init(truncating:) to make it clear that truncation, not regular rounding, occurs when converting from floating-point.<br></div><div><br></div><div><b>... masking shifts</b></div><div><br></div><div>The example claims that &quot;(30 as UInt8) &amp;&gt;&gt; 11&quot; produces 3, because it right-shifts 30 by 3. But isn&#39;t the bitWidth of UInt8 always 8 since it&#39;s a fixed-width type? Why should 11 get masked to 3 before the shift? (Also, it might be a good idea to choose examples with numbers whose base-ten representations don&#39;t look like valid binary. 😉) What use cases are there for masking shifts? I was under the impression that &quot;smart shifts&quot; were pretty much how the usual shift instructions already behaved.</div><div><br></div><div>(Minor: were the smart shift operators supposed to be included as BinaryInteger protocol requirements? I only see them in the &quot;heterogeneous shifts&quot; extension.)</div><div><br></div><div><b>... init&lt;T: BinaryInteger&gt;(_ source: T)</b></div><div><div><br></div><div>Now a thought experiment: suppose you wanted to write an arbitrary-precision BigInt, or any binary integer such as Int256. The BinaryInteger protocol requires you to provide init&lt;T:BinaryInteger&gt;(_ source: T). Given the source of type T, how do you access its bits? Is repeated use of word(at:) the recommended way? If so, it might be nice to include a &quot;wordCount&quot; returning the number of available words; otherwise I suppose the user has to use something like bitWidth/(8*MemoryLayout&lt;Int&gt;.<wbr>size), which is pretty ugly.</div><div><br></div></div><div><br></div><div><b>## FixedWidthInteger</b></div><div><br></div><div>Why is popcount restricted to FixedWidthInteger? It seems like it could theoretically apply to any UnsignedInteger.</div><div><br></div><div><br></div><div><b>## Heterogenous shifts, equality, and comparison</b></div><div><br></div><div>These look great. How will the default implementations be provided? (Equivalent question: how would a user define their own heterogeneous operators?) I suppose this works:</div><div><br></div><div><font face="monospace, monospace">    static func &amp;&gt;&gt; &lt;Other : BinaryInteger&gt;(lhs: Self, rhs: Other) -&gt; Self {</font></div><div><font face="monospace, monospace">        // delegate to the protocol requirement &amp;&gt;&gt;(Self, Self)<br></font></div><div><font face="monospace, monospace">        return self &amp;&gt;&gt; Self(extendingOrTruncating: rhs)</font></div><div><font face="monospace, monospace">    }</font></div><div><br></div><div>But for operations you can&#39;t delegate so easily... I&#39;m imagining trying to implement heterogeneous comparison (i.e. &lt; ) and the best I can come up with uses signum() and word(at:)...</div><div><br></div><div>Also, should these be protocol requirements so user-defined types can specialize them?</div><div><br></div><div><br></div><div><b>## Masking arithmetic</b><br></div><div><br></div><div>Do &amp;* and &amp;+ and &amp;- need their operands to have the same type, or could these be heterogeneous too (at least &amp;+ and &amp;-)?</div><div><br></div><div><br></div><div><div class="gmail_extra"><div><div class="gmail-m_9191639816149247006m_409108456507017154gmail-m_-421357865757461754gmail_signature"><div dir="ltr"><div>Jacob<br></div></div></div></div>
<br><div class="gmail_quote">On Fri, Jan 13, 2017 at 12:47 PM, Max Moiseev via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word">Hi everyone,<div><br></div><div>Back in June 2016 we discussed the new design of the integer types for the standard library. It even resulted in acceptance of <a href="https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md" target="_blank">SE-0104</a> for Swift 3. Unfortunately we were not able to implement it in time for the release.</div><div><br></div><div>But it was not forgotten, although, as time went by, a few changes needed to be made in order to reflect the current state of the language.</div><div>Without further introduction, please welcome the refined proposal to make integers in Swift more suitable for generic programming.</div><div><br></div><div>Available in this gist <a href="https://gist.github.com/moiseev/62ffe3c91b66866fdebf6f3fcc7cad8c" target="_blank">https://gist.github.com/m<wbr>oiseev/62ffe3c91b66866fdebf6f3<wbr>fcc7cad8c</a> and also inlined below.</div><div><br></div><div>Max</div></div></blockquote></div></div></div></div></div>