<div dir="ltr">On Sun, Jan 15, 2017 at 3:29 PM, 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">[ proposal link: <a href="https://gist.github.com/moiseev/62ffe3c91b66866fdebf6f3fcc7cad8c" target="_blank">https://gist.github.com/<wbr>moiseev/62ffe3c91b66866fdebf6f<wbr>3fcc7cad8c</a> ]<br><div class="gmail_extra"><div><div class="m_5460228561171012455m_-7385509867756785065gmail_signature"><div dir="ltr"><div><br></div></div></div></div>
<br><div class="gmail_quote"><span class="">On Sat, Jan 14, 2017 at 4:55 PM, Dave Abrahams 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></span><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=""><br>
Responding to both Jacob and Xiaodi here; thanks very much for your<br>
feedback!<br>
<span class="m_5460228561171012455m_-7385509867756785065gmail-"><br>
on Sat Jan 14 2017, Xiaodi Wu &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:</span></span><span class=""><span class="m_5460228561171012455m_-7385509867756785065gmail-"><br>
&gt; I think, in the end, it&#39;s the _name_ that could use improvement here. As<br>
&gt; the doc comments say, `Arithmetic` is supposed to provide a &quot;suitable basis<br>
&gt; for arithmetic on scalars&quot;--perhaps `ScalarArithmetic` might be more<br>
&gt; appropriate? It would make it clear that `CGVector` is not meant to be a<br>
&gt; conforming type.<br>
<br>
</span>We want Arithmetic to be able to handle complex numbers.  Whether Scalar<br>
would be appropriate in that case sort of depends on what the implied<br>
field is, right?<br></span></blockquote><div><br></div><div>I think &quot;scalar&quot; is an appropriate term for any field. The scalar-ness usually comes into play when it&#39;s used in a vector space, but using the term alone doesn&#39;t bother me.</div><span class=""><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">It&#39;s true that CGPoint and CGVector have no obvious sensible<br>
interpretation of &quot;42&quot;, and that&#39;s unfortunate.  The problem with<br>
protocols for algebraic structures is that there&#39;s an incredibly<br>
complicated lattice (see figures 3.1, 3.2 in<br>
<a href="ftp://jcmc.indiana.edu/pub/techreports/TR638.pdf" rel="noreferrer" target="_blank">ftp://jcmc.indiana.edu/pub/tec<wbr>hreports/TR638.pdf</a>) and we don&#39;t want to<br>
shove all of those protocols into the standard library (especially not<br>
prematurely) but each requirement you add to a more-coarsely aggregated<br>
protocol like Arithmetic will make it ineligible for representing some<br>
important type.<br></blockquote><div><br></div></span><div>Yep, it is quite complicated, and I understand not wanting to address all that right now; calling it ScalarArithmetic seems appropriate to clarify the limitations. FieldArithmetic might also be appropriate, but is less clear (+ see below about quaternions).</div><div><br></div><div>Daves Sweeris and Abrahams wrote:</div><div><br></div><div>&gt; &gt; I was under the impression that complex numbers are scalar numbers... although maybe not since once you get past, I think quaternions, you start losing division and eventually multiplication, IIRC. (I hate it when two of my recollections try to conflict with each other.) </div><span class=""><div>&gt;</div><div>&gt; Well, you can view them as 2d vectors, so I&#39;m not sure.  We need more of a numerics expert than I am to weigh in here.</div><div> </div></span><div>But complex numbers have multiplication and division operations defined (they form a field), unlike regular vectors in R². Meaning you can have a vector space over the field of complex numbers.</div><div><br></div><div>You still have multiplication and division past quaternions, but the quaternions are <b>not commutative</b>. This isn&#39;t really a problem in Swift, since the compiler never allows you to write an expression where the order of arguments to an operator is ambiguous. This means they are <b>not a field</b>, just a <a href="https://en.wikipedia.org/wiki/Division_ring" target="_blank">division ring</a> (a field is a commutative division ring). (I believe you can&#39;t technically have a vector space over a non-commutative ring; the generalization would be a <a href="https://en.wikipedia.org/wiki/Module_%28mathematics%29" target="_blank">module</a>. That&#39;s probably an argument for the name ScalarArithmetic over FieldArithmetic.)</div></div></div></div></blockquote><div><br></div><div>Hmm, the issue is that the integers are not a field. So, if we&#39;re going to have it all modeled by one protocol, maybe neither is the best term.</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 class="gmail_extra"><div class="gmail_quote"><div>Octonions are furthermore <b>not associative</b>, which is more of a problem since the standard library arithmetic operators are given an associativity. We can&#39;t give that up for regular numeric types, so someone working with octonions would just have to define their own non-associative operators (since there&#39;s no way for the protocol requirement to specify the operator associativity).</div><span class=""><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
That said, the ability to interpret integer literals as an arbitrary<br>
Arithmetic isn&#39;t used anywhere in the standard library, so I&#39;d like to<br>
consider undoing<br>
<a href="https://github.com/apple/swift/commit/de5b03ddc41be9c5ca5e15d5709eb2be069286c1" rel="noreferrer" target="_blank">https://github.com/apple/swift<wbr>/commit/de5b03ddc41be9c5ca5e15<wbr>d5709eb2be069286c1</a><br>
and moving ExpressibleByIntegerLiteral down the protocol hierarchy to<br>
BinaryInteger.<br></blockquote><div><br></div></span><div>+1</div><div><div class="h5"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
&gt;&gt; *## BinaryInteger*<br>
<span class="m_5460228561171012455m_-7385509867756785065gmail-">&gt;&gt;<br>
&gt;&gt; I&#39;m a little confused by the presence of init(extendingOrTruncating:) for<br>
</span>&gt;&gt; *all* binary integers. Why does it make sense to be able to write<br>
<span class="m_5460228561171012455m_-7385509867756785065gmail-">&gt;&gt; UInt16(extendingOrTruncating: (-21 as Int8)) ? In my mind, sign-extension<br>
&gt;&gt; only has meaning when the source and destination types are both signed.<br>
&gt;&gt;<br>
&gt;<br>
&gt; Here (just IMHO), I disagree. Since any binary integer can be truncated and<br>
&gt; any can be right-shifted, it makes sense for `init(extendingOrTruncating:)`<br>
&gt; to be available for all of them. If I understand the proposal correctly,<br>
&gt; `Int(extendingOrTruncating: (-1 as Int8))` would give you a different<br>
&gt; result than `Int(extendingOrTruncating: (255 as UInt8)`.<br>
<br>
</span>Yes it would.  But the real justification for this operation is generic<br>
programming with integers.  It isn&#39;t possible, today, to define:<br>
<br>
  init&lt;T:BinaryInteger&gt;(extendin<wbr>g:T) where T.isNarrowerThan(Self)<br>
  init&lt;T:BinaryInteger&gt;(truncati<wbr>ng:T) where T.isWiderThan(Self)<br>
<div><div class="m_5460228561171012455m_-7385509867756785065gmail-h5"><br>
&gt;&gt; Although I would not be against a clamp() function in the standard library,<br>
&gt;&gt; &quot;init(clamping:)&quot; sounds strange to me. What about calling it<br>
&gt;&gt; &quot;init(nearestTo:)&quot;?  One could also define a FloatingPoint version of<br>
&gt;&gt; init(nearestTo:), i.e. lround(). For maximum annoyance and explicitness,<br>
&gt;&gt; you could even rename the existing init(_:) to init(truncating:) to make it<br>
&gt;&gt; clear that truncation, not regular rounding, occurs when converting from<br>
&gt;&gt; floating-point.<br>
&gt;&gt;<br>
&gt;<br>
&gt; I would disagree with that as well; the existing `init(_:)` truncates the<br>
&gt; fractional part but errors if that value is outside the representable<br>
&gt; range, while the word &quot;truncating&quot; makes it sound like something is done to<br>
&gt; make any possible source value give you a destination value (a la<br>
&gt; &quot;extendingOrTruncating&quot; for integers).<br>
&gt;<br>
&gt; Meanwhile, &quot;nearest to&quot; is problematic for me because either 127 and 129 is<br>
&gt; &quot;nearest to&quot; 128, and neither integer is &quot;nearest to&quot; 500, yet<br>
&gt; `Int8(clamping: 128)` and `Int8(clamping: 500)` both give you 127. This<br>
&gt; operation is very different from lround() for floating point, which in<br>
&gt; Swift is `rounded(.toNearestOrAwayFromZ<wbr>ero)` (or just `rounded()`).<br></div></div></blockquote><div><br></div></div></div><div>127 and 129 are both nearest to 128, but both of them are not Int8s. The &quot;Int8(nearestTo: 128)&quot; would be 127.</div></div></div></div></blockquote><div><br></div><div>Well, now we&#39;re splitting hairs, but I don&#39;t think this is among the more plausible rationalizations of a hypothetical init(nearestTo:). Either you look for the integer(s) nearest to (128 as Int) in the set of all Int values. Then, the nearest integers are equally 127 and 129. You attempt to convert both to Int8 and trap (unless you first _clamp_ your results to the range [-128, 127] before attempting to convert). Or, you look for the Int8 value(s) nearest to 128 in the set of all possible Int8 values. However, since the distance between (128 as Int) and any Int8 is undefined, (127 as Int8) is strictly speaking no nearer to (128 as Int) than is (-128 as Int8) or any other Int8 value.</div><div><br></div><div>By contrast, the word `clamping` tells you that something is first done to (128 as Int)--namely, it is clamped to the range [-128, 127]--and then the result is converted to an Int8; thus, this function never traps.</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 class="gmail_extra"><div class="gmail_quote"><span class=""><div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div class="m_5460228561171012455m_-7385509867756785065gmail-h5">
&gt;<br>
&gt; In both these cases, I think it&#39;s important to use spellings that<br>
&gt; distinguish doing things to the fractional part of floating point values<br>
&gt; and doing things to the binary representation of integer values. I think<br>
&gt; there&#39;s great value in using the term &quot;clamp&quot;, which is very different from<br>
&gt; &quot;nearest&quot;; and in using an unlabeled `init(_:)` for initializing from FP<br>
&gt; values, which is most similar to the unlabeled `init(_:)` for initializing<br>
&gt; from integer values, as opposed to your suggested `init(truncating:)` which<br>
&gt; connotes some similarity to `init(extendingOrTruncating:)` for integer<br>
&gt; values.<br>
<br>
</div></div>+1<br>
<br>
&gt; *... masking shifts*<br>
<span class="m_5460228561171012455m_-7385509867756785065gmail-">&gt;&gt;<br>
&gt;&gt; The example claims that &quot;(30 as UInt8) &amp;&gt;&gt; 11&quot; produces 3, because it<br>
&gt;&gt; right-shifts 30 by 3. But isn&#39;t the bitWidth of UInt8 always 8 since it&#39;s a<br>
&gt;&gt; fixed-width type?<br>
<br>
</span>Yes.<br>
<span class="m_5460228561171012455m_-7385509867756785065gmail-"><br>
&gt;&gt; Why should 11 get masked to 3 before the shift?<br>
<br>
</span>Because those are the semantics of masking shift?<br></blockquote><div><br></div></span><div>Ah, I see why I was confused (the point is that  2³ = 8 = bitWidth). Does this mean that masking shifts only work when the bitWidth is a power of two? Otherwise, there&#39;d be no way to reduce the shift range to exactly 0..&lt;bitWidth using a mask.</div><div><div class="h5"><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
You can think of masking shift as an optimization akin to using &amp;+ to<br>
add signed numbers when you know it can&#39;t overflow.  It&#39;s an expert&#39;s<br>
tool.  If you want semantics that always make sense, use regular shift.<br>
<span class="m_5460228561171012455m_-7385509867756785065gmail-"><br>
&gt;&gt; (Also, it might be a good idea to choose examples with numbers whose<br>
&gt;&gt; base-ten representations don&#39;t look like valid binary. 😉)<br>
<br>
</span>Good point.<br>
<span class="m_5460228561171012455m_-7385509867756785065gmail-"><br>
&gt;&gt; What use cases are there for masking shifts? I was under the<br>
&gt;&gt; impression that &quot;smart shifts&quot; were pretty much how the usual shift<br>
&gt;&gt; instructions already behaved.<br>
<br>
</span>No, sadly not!  The way the usual shift instructions behave is that if<br>
you shift by a negative amount or you overshift, you get undefined<br>
behavior, which gets expressed in various fun ways at runtime!<br>
<span class="m_5460228561171012455m_-7385509867756785065gmail-"><br>
&gt;&gt; (Minor: were the smart shift operators supposed to be included as<br>
&gt;&gt; BinaryInteger protocol requirements? I only see them in the &quot;heterogeneous<br>
&gt;&gt; shifts&quot; extension.)<br>
<br>
</span>They don&#39;t need to be requirements, as they&#39;re defined entirely in terms<br>
of other (required) operations.  I&#39;d be interested in any arguments you<br>
might have for making them requirements, though.<br>
<br>
&gt;&gt; *... init&lt;T: BinaryInteger&gt;(_ source: T)*<br>
<span class="m_5460228561171012455m_-7385509867756785065gmail-">&gt;&gt;<br>
&gt;&gt; Now a thought experiment: suppose you wanted to write an<br>
&gt;&gt; arbitrary-precision BigInt, or any binary integer such as Int256. The<br>
&gt;&gt; BinaryInteger protocol requires you to provide init&lt;T:BinaryInteger&gt;(_<br>
&gt;&gt; source: T). Given the source of type T, how do you access its bits? Is<br>
&gt;&gt; repeated use of word(at:) the recommended way?<br>
<br>
</span>Yes.<br>
<span class="m_5460228561171012455m_-7385509867756785065gmail-"><br>
&gt;&gt; If so, it might be nice to include a &quot;wordCount&quot; returning the number<br>
&gt;&gt; of available words; otherwise I suppose the user has to use something<br>
&gt;&gt; like bitWidth/(8*MemoryLayout&lt;Int&gt;.<wbr>size), which is pretty ugly.<br>
<br>
</span>good catch; countRepresentedWords is in the prototype<br>
(<a href="https://github.com/apple/swift/blob/new-integer-protocols/stdlib/public/core/Integers.swift.gyb#L1521" rel="noreferrer" target="_blank">https://github.com/apple/swif<wbr>t/blob/new-integer-protocols/s<wbr>tdlib/public/core/Integers.swi<wbr>ft.gyb#L1521</a>),<br>
and it should be in the proposal.<br>
<br>
&gt;&gt; *## FixedWidthInteger*<br>
<span class="m_5460228561171012455m_-7385509867756785065gmail-">&gt;&gt;<br>
&gt;&gt; Why is popcount restricted to FixedWidthInteger? It seems like it could<br>
&gt;&gt; theoretically apply to any UnsignedInteger.<br>
&gt;&gt;<br>
&gt;<br>
&gt; You can perfectly legitimately get a popcount for a signed integer. It&#39;s<br>
&gt; just looking at the binary representation and counting the ones. But then<br>
&gt; with two&#39;s complement, it&#39;d have to be restricted to FixedWidthInteger and<br>
&gt; not BinaryInteger, because the same negative value would have a different<br>
&gt; popcount depending on the type&#39;s bitwidth.<br>
<br>
</span>Right, or to put it differently, the popcount of a negative BigInt would<br>
always be inifinite.<br></blockquote><div><br></div></div></div><div>Makes sense, but infinity has no representation in Int, so what would the popcount be?</div></div></div></div></blockquote><div><br></div><div>I think the point here is that not all BigInt values would have a representable popcount, justifying the requirement being on FixedWidthInteger as opposed to BinaryInteger.</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 class="gmail_extra"><div class="gmail_quote"><span class=""><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<span class="m_5460228561171012455m_-7385509867756785065gmail-"><br></span>&gt;&gt; *## Masking arithmetic*<br>
<span class="m_5460228561171012455m_-7385509867756785065gmail-">&gt;&gt;<br>
&gt;&gt; Do &amp;* and &amp;+ and &amp;- need their operands to have the same type, or could<br>
&gt;&gt; these be heterogeneous too (at least &amp;+ and &amp;-)?<br>
<br>
</span>I don&#39;t know what semantics you&#39;re imagining for heterogeneous &amp;+.  What<br>
type would it return?  What mask would it use? </blockquote><div><br></div></span><div>I was thinking of these as overflow rather than masking operators; i.e. the lhs type would be allowed to overflow if the rhs value were too large. </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>