Really? In what case? It’s just an expression and the entire statement just uses the expression result.
Of course when optimising code like this, I think it’s important to look at the generated assembly anyway and then you can be sure that it does what you expect on the compilers you intend on supporting (doubly so when you want to generate conditional moves — I’ve found that to be a bit of a puzzle where I sometimes need to move things around as the obvious code still generated a branch), but at least GCC and Clang won’t generate a branch for using just a comparison. Maybe it’s not the compiler and instead the target architecture? In x86, comparisons set flags, so by themselves aren’t branches. In any case, I recommend using compiler explorer when working on code where this matters.
Setting the CPU flag after a comparison doesn't do anything useful yet, you also need to perform an addition with 1 or do nothing depending on the flag, and selecting between these two options is usually done with a conditional branch, unless the CPU can execute ALU instructions conditionally (ARM can do this, x86 only has conditional mov AFAIK).
Can it? I understand it’s always possible to decompose that to
if (a[i] > 0)
return 1
else
return 0
end
But why would a compiler do that?
Comparison operations are basic primitives that usually store their result into a register. With branching comparison operators potentially also available, but if there’s a branching comparator operation in your ISA, then there’s almost certainly also a pure comparator operation in your ISA, because you can always compose a branching comparator from simple comparison operation followed by a basic equality comparison of the result.
So I guess my question is, while it’s technically possible for a compiler to compile this into a branching operations, under what circumstances would a compiler actually choose to do that, given there’s isn’t a clear benefit?
In the branchless version, the CPU has to wait for the comparison to resolve before it can start executing the add for the next loop iteration. However, if the branch is predictable, the CPU can assume the result of the conditional and does not need to wait to add one or not. I wrote a more in depth comment about why this is true a few months ago: https://news.ycombinator.com/item?id=37245594
If I alter the code slightly to do `result += (a[i] == 0) * 2`, gcc emits a branch if the comparison is predictable: https://godbolt.org/z/df3fsoYK8
Here is a benchmark: https://quick-bench.com/q/NSGHu_wfhrMXp0-pZQp9qybCIok. Note how the branchless version takes the same time for the random and the zeroes vector, while the branch version is faster when the branch is predictable but slower when the branch is not predictable.
> Comparison operations are basic primitives that usually store their result into a register.
In one of the most common processor architectures (the x86 family), comparison operations do store their result into a register, but it's the flags register, which can't be used directly in arithmetic operations. So you have to follow a comparison operation with either a conditional branch or a conditional move (and earlier processors in the x86 family didn't have conditional moves).
> So I guess my question is, while it’s technically possible for a compiler to compile this into a branching operations, under what circumstances would a compiler actually choose to do that, given there’s isn’t a clear benefit?
It depends on the compiler heuristics and on the surrounding code; for instance, it might decide that "compare; conditional branch over next instruction; increment" is better than "copy to second register; increment second register; compare; conditional move from second register", because it uses one less register (the x86 family is register starved) and one less instruction (relevant when optimizing for size).
> So you have to follow a comparison operation with either a conditional branch or a conditional move (and earlier processors in the x86 family didn't have conditional moves).
The x86 family has the `setCC` instructions [^1] that move bits from the flag register to a general purpose one. Example from godbolt, see `setg`:
The most egregious problem caused by this that I've encountered is an almost complete inability to use email 2FA on websites because my phone will kill the browser as soon as I switch to my inbox, and when I go back to the browser I'm back on the login screen which will generate a new one-time-password and make the one I have in my clipboard worthless. I've also encountered the exact same problem with 2FA using an authenticator app, though since the codes are valid for ~30 seconds or so, if I manage to enter my credentials fast enough or they auto-fill, at least the code I copied is still valid.
- no readonly properties: You can use a getter. Or define the property as non-writable, the syntax isn't nice but in my opinion it's still much nicer than what the article proposes.
Some of the points are just a matter of taste ("this" is awkward)
There's the implementation itself which forces you to use non-idiomatic code for no good reason or benefit (Class.init instead of new, just why? You can absolutely return a constructor function there while preserving everything else)
Doing what the article proposes also destroys the ability to do instanceof checks because the prototype of instances is not set (can be fixed), and inheritance is severely limited if you want to preserve any of the purported benefits. You might say that inheritance is actually not a good thing and so it's a feature, not a bug, but if that's your opinion why are you trying to mimic a class?
Agreed. I spent a small epoch of my career trying to make js have "classes" in the heady days of OOP. It took a bit to realize that idiomatic js didn't need them. Besides being sold so hard on OOP as a concept, failing to understand prototypes was one of my biggest mistakes. By the time they landed, I was actually pretty disappointed to see the language get classes.
> By the time they landed, I was actually pretty disappointed to see the language get classes.
TBF classes are just a layer of syntactic sugar over the (awful) prototypal system (which somewhat sadly few were interested in making better let alone good).
Behind the scenes, they pretty much just create a ctor function and prototype function, except you don't have to mess with the terrible `Object.create` and `.prototype =` nonsense.
Abandoning constructors and going full-on with prototypes would be an other thing entirely, but the reality is that javascript is not very good at it so it's not very fun (except as a proof of concept / investigation of prototype based OO), and pretty much nobody is interested.
Yeah, that's fair. I guess I don't really use prototypes anymore either. I find modules and closures are intuitive and powerful, though very different conceptually from classes/prototypes, tools for handling things like private state. Really OOP is what I've grown away from over the years in most languages. I even enjoy writing C++ in this style since its capabilities around things like closures has improved, anonymous namespaces make for a similar "module" scope to what you find in js.
There was not. There is now but for the better part of a decade it was just... Something you were supposed to have learned from a youtube video or a friend or something.
How exactly is that a non sequitur? It should be evident that if you jail the innocent party, the guilty party would still be at large, case closed, authorities would no longer be looking for them.
The whole premise of this one or the other thing is flawed. You can increase conviction of the guilty while also protecting the innocent depending on the procedures taken. The "how" matters at lot. So when you ask people stuff like how many guilty men should go free, it's a complete farce that is easily manipulated based on how you pose the question, methods, and outcomes in the fictional scenario. It takes away focus from the actual policies/solutions.
A lot of the comments seem to talk about the inevitable AI event horizon but unless I'm misreading this article the results are flat out bad. Even the 6 billion parameters model barely scratches a 50% success rate on a tiny problem that is trivial to fix for any human with basic knowledge of programming. Note the log scale of the graph.
Yeah, I am also struggling to interpret the metrics in this post positively.
The 50% success rate is also best out of 3200 completions. For best out of 1 completion, the success rate is in low single digits.
I think the lesson here is that these models bring a lot more value when:
1. you have unit tests,
2. can afford compute/time to let the model try many solutions,
3. have enough isolation to run unverified code.
> (damnit, of course calculating the permutations of a list is n-squared, but this is an interrogation of the random trivia I can manage to recall and I feel like a deer in the headlights)
With this statement I'm inclined to believe the title. Last I checked there are (n-1)! permutations for a list of length n. Not knowing this off the top of your head is fine, but making this kind of comment is an unforced error and it doesn't reflect well on the author.
Does seem a bit odd at second glance, seems like hitting the back button undos scrolling instead of navigating back to HN, depending on how much I scrolled. Maybe it's a feature though. Firefox for Android 107.1.0 with uBO.
In Brave I see "Enter a caption (optional)" on every picture. <span class="caption public_hide" contenteditable="false" id="78a560_1776">Enter a caption (optional)</span>.
That is in fact incredibly useful