<div dir="ltr">On Sat, Jan 14, 2017 at 1:32 AM, Jacob Bandes-Storch 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><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><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/<wbr>jtbandes/<wbr>93eeb7d5eee8e1a7245387c660d53b<wbr>03#file-affine-swift-L16-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></div></blockquote><div><br></div><div>I think, in the end, it&#39;s the _name_ that could use improvement here. As the doc comments say, `Arithmetic` is supposed to provide a &quot;suitable basis for arithmetic on scalars&quot;--perhaps `ScalarArithmetic` might be more appropriate? It would make it clear that `CGVector` is not meant to be a conforming type.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div></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.</div></div></div></blockquote><div><br></div><div>Here (just IMHO), I disagree. Since any binary integer can be truncated and any can be right-shifted, it makes sense for `init(extendingOrTruncating:)` to be available for all of them. If I understand the proposal correctly, `Int(extendingOrTruncating: (-1 as Int8))` would give you a different result than `Int(extendingOrTruncating: (255 as UInt8)`.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div></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></div></blockquote><div><br></div><div>I would disagree with that as well; the existing `init(_:)` truncates the fractional part but errors if that value is outside the representable range, while the word &quot;truncating&quot; makes it sound like something is done to make any possible source value give you a destination value (a la &quot;extendingOrTruncating&quot; for integers).</div><div><br></div><div>Meanwhile, &quot;nearest to&quot; is problematic for me because either 127 and 129 is &quot;nearest to&quot; 128, and neither integer is &quot;nearest to&quot; 500, yet `Int8(clamping: 128)` and `Int8(clamping: 500)` both give you 127. This operation is very different from lround() for floating point, which in Swift is `rounded(.toNearestOrAwayFromZero)` (or just `rounded()`).</div><div><br></div><div>In both these cases, I think it&#39;s important to use spellings that distinguish doing things to the fractional part of floating point values and doing things to the binary representation of integer values. I think there&#39;s great value in using the term &quot;clamp&quot;, which is very different from &quot;nearest&quot;; and in using an unlabeled `init(_:)` for initializing from FP values, which is most similar to the unlabeled `init(_:)` for initializing from integer values, as opposed to your suggested `init(truncating:)` which connotes some similarity to `init(extendingOrTruncating:)` for integer values.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><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></div></blockquote><div><br></div><div>You can perfectly legitimately get a popcount for a signed integer. It&#39;s just looking at the binary representation and counting the ones. But then with two&#39;s complement, it&#39;d have to be restricted to FixedWidthInteger and not BinaryInteger, because the same negative value would have a different popcount depending on the type&#39;s bitwidth. I&#39;d disagree strongly with removing popcount from signed binary integers. However, I suppose the same requirement could be applied to both FixedWidthInteger and UnsignedInteger.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><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="m_-2176513483445216513gmail-m_9191639816149247006m_409108456507017154gmail-m_-421357865757461754gmail_signature"><div dir="ltr"><div>Jacob<br></div></div></div></div><span class="">
<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></span></div></div></div></div>
<br>______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br>
<br></blockquote></div><br></div></div>