<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Sep 8, 2016 at 12:17 AM, Jacob Bandes-Storch <span dir="ltr"><<a href="mailto:jtbandes@gmail.com" target="_blank">jtbandes@gmail.com</a>></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 dir="ltr"><div class="gmail_extra"><span class="gmail-"><div><div><div dir="ltr"><div>On Wed, Sep 7, 2016 at 10:02 PM, Xiaodi Wu <span dir="ltr"><<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>></span> wrote:<br></div></div></div></div></span><div class="gmail_quote"><span class="gmail-"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span>On Wed, Sep 7, 2016 at 11:48 PM, Jacob Bandes-Storch <span dir="ltr"><<a href="mailto:jtbandes@gmail.com" target="_blank">jtbandes@gmail.com</a>></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 dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span>On Mon, Sep 5, 2016 at 1:19 PM, Xiaodi Wu <span dir="ltr"><<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>></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 dir="ltr"><span style="font-size:12.8px;white-space:pre-wrap">This suggestion has been pitched earlier and I've expressed my opinion in those earlier threads, but I'll repeat myself here:</span><div><span style="font-size:12.8px;white-space:pre-wrap"><br></span></div><div><span style="font-size:12.8px;white-space:pre-wrap">I'm hugely opposed to such changes to the precedence table. </span><span style="font-size:12.8px;white-space:pre-wrap">Those of us who work with bitwise operators on a regular basis have memorized their precedence in Swift (and other languages) and rely on such precedence to write readable, correct code without excessively nested parentheses.</span></div></div></blockquote><div><br></div></span><div>Could you point me towards some examples of such code? I don't write it very often, so I don't feel I can really evaluate this. (This seems analogous to the "terms of art" categorization from the API Design Guidelines threads.) Much of the code I would normally write using bitwise operators has been replaced with the SetAlgebra protocol methods provided on OptionSet types.</div></div></div></div></blockquote><div><br></div></span><div>Gladly. These (which cannot be copied verbatim into Swift, as C operator precedences are different):</div><div><a href="https://graphics.stanford.edu/~seander/bithacks.html" target="_blank">https://graphics.stanford.edu/<wbr>~seander/bithacks.html</a><br></div><div><br></div><div>Lest you think I'm giving you a C example because I don't actually use such things in Swift, here's me using some of these:</div><div><a href="https://github.com/xwu/FlowKit/blob/master/Source/BitVector.swift" target="_blank">https://github.com/xwu/FlowKit<wbr>/blob/master/Source/BitVector.<wbr>swift</a><br></div><div><br></div><div>(Note that this specific example will soon be obsolete with new integer protocols.)</div></div></div></div></blockquote><div><br></div></span><div>Both of these actually seem to make pretty careful use of parentheses in expressions with mixed-precedence infix operators.</div></div></div></div></blockquote><div><br></div><div>I do try to be very careful, yes :) If I recall correctly, I have actually hardcoded the order of operations entirely with parentheses, disregarding Swift's precedence table entirely. The reason for this was twofold: (1) at the time I first wrote the code, it was the very first time I'd used Swift's bitwise operators, which have different precedences from C; (2) I was porting over a numerical recipe from C, and I preserved the parentheses that were required in that language for my own sanity.</div><div><br></div><div>I shared that example in part because I think it illustrates a salient point here. Chris Lattner--in his comment in the previous thread on the topic--challenged those proposing this change to show "evidence of common bugs" or "evidence of actual user confusion." By contrast, my experience has been (both from reading and writing code) that there's typically very good code hygiene in instances where mixed precedence operators are used in practice, and (with respect to writing code) I certainly don't consider myself an unusually careful programmer.</div><div><br></div><div>Clearly, no one disputes that parentheses can be wise in some instances even when they're not required. Essentially, by proposing removal of precedence relations, the question you're raising is: should parentheses always be required [in some subset of circumstances]?</div><div><br></div><div>My take on this issue, if I may rephrase, is simply this:</div><div><br></div><div>1. When I've been confused about the order of operations as I'm *writing* code, I've put in parentheses without hesitation. From what I've gathered from this list, essentially everyone else does this as well. Would removing precedence relations improve this aspect of using operators (i.e. writing code)? It does not seem so, since it would make required what people already use according to their best judgment.</div><div><br></div><div>2. When I've been confused about the order of operations as I'm *reading* code, I simply turn to the precedence table. Three points on the experience of reading code using operators:</div><div>(a) In practice, I've rarely been confused about the order of operations, since (as mentioned above) I find that those who write the code tend to clarify for the reader anyway, if only for their own sanity while writing the code.</div><div>(b) When I've found myself confused, as in the case with some of the "Bit Hacks" linked above, this issue has been the least of my problems, as formulas that mix these operators have proved difficult to digest even with all the parentheses put in.</div><div>(c) It's well nigh impossible to read the precedence table incorrectly: the _concept_ of operator precedence must be second-nature to any person who knows what multiplication is, so it's simply a matter of finding out what the actual precedence _is_; no ambiguity persists after that information is supplied.</div><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"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>In the former, I find only a small handful of cases where & is mixed with +, *, or / — seemingly the minority.</div></div></div></div></blockquote><div><br></div><div>I haven't gone through to tabulate what proportion of those formulas mix certain categories of operators with others. It's not a particularly useful piece of information, I'd argue, since no one is implementing this entire book of recipes and calling each function a roughly equal number of times in their code. The subset of these recipes that I've studied (or equivalently, have been interested in using or actually have used) mix operators pretty frequently. It all comes down to what code you're writing. In some ways, this gets to another tentpole of my argument to preserve precedences. In some ways, all arguments about their addition, removal, or modification, seem to have boiled down to a subjective judgment as to their current appropriateness or how common their use or misuse might be, but with strikingly little data for evidence.</div><div><br></div><div>Case in point (without meaning to calling you out specifically; just that our conversation is the freshest in my mind, and it's late and my mind is foggy): you mentioned that you were content with the current precedence of bitwise <<, because you could see how it was related to exponentiation; but you were not happy with the precedence of &, because you could not see how it was related to multiplication. However, by the same token, I can see both how << is related to exponentiation and how & is related to multiplication, and thus I am content with their precedence. The counter-counterargument in the previous thread was that the relationship between & and multiplication was not sufficiently obvious or relevant, but of course that's in turn also a subjective judgment. I can equally argue that the relationship between << and exponentiation is not sufficiently relevant either, or that the relationship between & and multiplication is crucially relevant...</div><div><br></div><div>Given that Swift has already revised operator precedence (as compared to the C family of languages), and given that Swift 4 makes some promise of avoiding source-breaking changes where possible, the above style of argumentation seems woefully insufficient to justify another change. Rather, I could be swayed by objective evidence that users *commonly* expect some operator to work a certain way, leading to actual erroneous real-world code. However, it does not seem that such evidence is forthcoming. By contrast, let's visit some of the not-so-real-world examples we've seen so far:</div><div><br></div><div>Erica thought that `let y = 5 + (x ?? 2)` required one too many sets of parentheses. Removal of the precedence relation between ?? and arithmetic operators does nothing to address this gap between Swift's syntax and Erica's expectations. In fact, we would be making the parentheses mandatory in more scenarios than are required currently.</div><div><br></div><div>Let's revisit some of Vladimir's examples:</div><div><br></div><div><span style="font-size:12.8px">I believe that `let result = a || (b) ? isOne() : isTwo()` is implausible for several reasons. I will give only two. First, I have never encountered any actual attempt to evaluate four Boolean values in some combination of a binary operator and the ternary operator. Second, it is unlikely that a writer of code would try _but fail_ at correctly surrounding the intended portions of that statement with parentheses (i.e. either `(a || b)` or `(b ? isOne() : isTwo())`), instead ineffectually surrounding `b` with parentheses.</span><br></div><div><br></div><div>`<span style="font-size:12.8px">s << (x == 10) ? "10" : "not 10"` is impossible. Firstly because no such `<<` operator is defined in the standard library or core libraries, and I do not know of any Swift library that does define such an operator. Secondly because Swift greatly discourages (to my knowledge) the overloading of operators with entirely different semantics. Thirdly because even if one such operator is defined but the order of operations is not as the writer intended, the expression would not compile because of a type mismatch. Fourthly, because even if two such operators are defined so that the expression would compile, the result would differ in type (from the expected type) if the order of operations is not as the writer intended, and any further non-trivial use of the result would lead to an error at compile time.</span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">You and I seem to agree that `</span><span style="font-size:12.8px">let i = 4 << 1 + 3` is rather reasonable. But we needn't use such a subjective judgment. Quite simply, you would not write such a line of code if you weren't sure of the precedence of << relative to +. You'd use parentheses. You wouldn't read such a line of code just assuming a certain precedence relation if you were foggy on bitshifting operators; you would look it up. I am not sure how one can make an unintended error either reading or writing this line of code[*].</span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">[*] Actually, I can see precisely one way to make such an unintended error, since I have actually done so. It has to do with Swift having moved away from the classical C-family operator precedence table. I would actually not be opposed to making changes that guard against such an error.</span></div><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"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="gmail-"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span><div><br></div></span><div>The proposals include both breaking precedence relations and changing them; changing them will essentially always cause silent changes in existing code. Removing relations won't; however, it will necessitate sometimes difficult migrations, as formulas are complicated.</div></div></div></div></blockquote><div><br></div></span><div>I would think (hope) that any removals could easily yield automatic migrations by adding parens where they were previously implied. I would only be concerned with the possibility that such a migration would affect type-checking speed (an area that already needs improvement, and can be exacerbated by large expressions). </div></div></div></div>
</blockquote></div><br></div><div class="gmail_extra">Certainly, automatic migrations will help avoid certain errors. Our frail human brains make certain mistakes possible when adding or removing parentheses by hand. Things like distributing the minus sign, etc...</div></div>