"...who firmly believed that the terser your code, the faster it ran. The author crammed multiple side effects into a single expression, used ternary operators like they were going out of style, and generally believed that run time was proportional to the number of semicolons executed, and every variable killed a puppy."<p>How does one go about countering that mentality in some rule of thumb fashion if at all possible? Could a disassembly illuminate identical push/pop operations on the memory stack as explicit intermediate variables would? Maybe a simple intermediate result expansion timing profile side by side the terse code's profile?
I wonder if the first one was meant to be<p><pre><code> a -= a * a;
</code></pre>
which evolved from<p><pre><code> a *= a;
</code></pre>
after the author thought "I need to subtract its square from itself, not just square it". I can see how this could occur in numerical code.<p>I've noticed there are two opposing schools of thought on issues of "insane code" like this; on one side there's "use the language to the fullest if it makes sense to", and on the other is "avoid anything that might be the slightest bit confusing". I think that taking either of those to their logical conclusion is not a good idea --- in the former case, you'll end up with extremely dense and (initially) difficult-to-understand code, but the latter case will cause a gradual degradation of code into something approaching the verbosity of Asm, but with none of the benefits (e.g. "ternary operators are confusing, don't use them; multiple levels of precedence are confusing, so always fully parenthesise expressions; nested parentheses are hard to read, so don't use them either and only do one operation per statement; boolean expressions are confusing, so always use if/else; nested if/else are confusing, so don't nest and always refactor to use a function call, etc. etc.)<p>It does seem that different languages vary in where they are on this scale, with more "exotic" ones like APL tending highly towards the former (interesting related discussion: <a href="https://news.ycombinator.com/item?id=13565743" rel="nofollow">https://news.ycombinator.com/item?id=13565743</a> ) and C#/Java towards the latter. The ideal is probably somewhere in the middle.
I use the ternary operator all the time.<p><pre><code> result = boolean_flag
? do_this()
: do_that();
</code></pre>
I think it's less noisy and nicer to look at then an if-else, provided the statements aren't too long. God forbid multiple side effects though, even in languages with less complicated sequencing rules than C/C++.
> First of all, there will be a lot of false positives. For example, you might write<p><pre><code> total_cost = p->base_price + p->calculate_tax();
</code></pre>
> This would raise the warning because the compiler observes that the calculate_tax method is not const, so it is worried that executing the method may modify the base_price, in which case it matters whether you add the tax to the original base price or the updated one. Now, you may know (by using knowledge not available to the compiler) that the calculate_tax method updates the tax locale for the object, but does not update the base price, so you know that this is a false alarm.<p>I think the warning in that case is still fair, and I'd be perfectly happy to get it. calculate_tax() could be modified to affect base_price with this compilation unit being none the wiser.
v8 at one point made inlining decisions based on character count. Terse code would be inclined more aggressively, and even adding comments could defeat inlining: <a href="https://top.fse.guru/nodejs-a-quick-optimization-advice-7353b820c92e" rel="nofollow">https://top.fse.guru/nodejs-a-quick-optimization-advice-7353...</a>
Two unfashionable lessons that I learned when I was a practicing programmer rather than a hobbyist and loathsome manager.<p>1. Code is a communication system : between you and the next person to touch it. You are telling the other person how you made this work. Invest in this because the next person will probably be you in six months.<p>2. Compilers and type systems are your friends. Write code that extracts errors from the compiler by explicitly constraining things as much as you can afford to do. Avoiding typing or checking via long methods or low level datatypes is bad. Short typed, functional methods and high level data types are good.
After gaining a bit of experience programming, I've developed for myself the following rule:<p>If I feel particularly smart and proud after writing a piece of code, I look at it again and remove some smartness in favour of readability.<p>Unless it's absolutely performance critical, in which case I try to comment the hell out of what's going on.
I used to think I had a pretty good grasp on how the compiler was going to encode things.<p>After spending months looking at disassembled FreeBSD kernel C code in a profiler, trying to hunt down cache misses, I'm realize that it is hard to count on anything and that my instincts, even after 25+ years of C programming, are often wrong.
I wonder if, from this: He gave as one example a book from an apparently-successful author (sales of over four million and counting) who firmly believed that the terser your code, the faster it ran. The author crammed multiple side effects into a single expression, used ternary operators like they were going out of style, and generally believed that run time was proportional to the number of semicolons executed, and every variable killed a puppy.<p>If the described author could be identified? Perhaps not absolutely, but they do have some specific stylistic quirks combined with a particular sales level.
> The people who would benefit from the warning don't have the necessary background to understand it.<p>In my experience, this is accurate, but underscores a teaching opportunity. If you show Joe Beginner how to get the warnings, explain how they apply to the code and why the warning was good, they may slowly begin to appreciate the warnings. So that even if they don't understand, they won't necessarily dismiss the warning next time -- instead they'll go ask for help.
From one of the comments there,<p>“<i>Nathan Reed</i><p>"<i>July 19, 2017 at 4:34 pm</i><p>" <i>Didn't you just write such code with a straight face yourself only yesterday? ;) In your bytecode interpreter example:</i><p><pre><code> memory[NextUnsigned16()] = NextUnsigned8();
</code></pre>
"<i>Presumably the NextUnsigned8/16 functions have side effects of advancing a buffer pointer, so this is nearly the equivalent of p[x++] = ++x.</i>"
Closest I've come to really embracing that kind of thing is <a href="https://github.com/serprex/pythonaes/tree/master/aespython" rel="nofollow">https://github.com/serprex/pythonaes/tree/master/aespython</a><p>NB it really is faster<p>edit: nvm, Crumb is way more that kind of thing: <a href="https://github.com/serprex/Crumb/blob/master/C3.py" rel="nofollow">https://github.com/serprex/Crumb/blob/master/C3.py</a>
I forgot I concocted that little devil
What does:<p><pre><code> a -= a *= a;
</code></pre>
Do?<p>Looking through C# docs (which I assume this is, but don't have experience with), it seems A's value is changed to be the previous value of a, minus itself (ie 0) multiplied by a? In other words:<p><pre><code> a = 0
?</code></pre>
The pythonic example I've seen not once:<p>{"some": "dict"}.setdefault("some", foo())<p>while expecting foo() to be short-circuited.