Marco Alka Don't feel stupid. It's something I've noticed the past few decades of programming and it's all about background and exposure. I'm actually writing a rather lengthy blog post/article on the topic of such things, hope to have it done by saturday
People who write in C, coming from C backgrounds, simply don't think in terms of do/while. They will jump through all sorts of crazy hoops of recursive function calls, while(true), even trying to get jump/goto labels into their compilers because even if they're aware "do" exists, they just aren't primed to think that way. All they've ever seen and all they've ever done is while(){} that so they never even think of do{}while();
Because languages like PHP, JavaScript, Java, and so forth are C syntax -- for all intents and purposes nothing more than C tarted up in a slinky dress with theatrical makeup and 4" stilleto CFM pumps -- everyone using those languages just copies that model and mindset.
But those of us who learned Assembler or Wirth syntax languages think in terms of "the condition is at the end of the loop". It's why "for" loops feel counterintuitive to me even after some three and a half decades of using them... Since I still in my head think "set the counter to the number of loops, then decrement until zero".
Which is why this:
var i = 100;
do {
} while (!(--i));
Still feels more "correct' in my mind than a for loop.
Or something as simple as DOM walking, where if/do/while is the more powerful way, even if you do need a recursive call. Let's say you wanted to walk a TR element's node tree with a callback for all the cells inside it.
It's laughable how many people would do this:
function nodeAllCells(e, callback) {
for (var i = 0; i < e.cells.length; i++) {
callback(e.cells[i]);
}
}
But then even said for loop / element index is inefficient when it comes to objects or nodelists. Czech this out:
function nodeAllCells(e, callback) {
for (var i = 0, cell; cell = e.cells[i]; i++) {
callback(cell);
}
}
That's actually the fastest way to iterate through a nodeList, because it removes an unnecessary comparison. So long as all the items in an array-like are not loose-false, it is faster in JS to iterate through them by assignment, since assignment past the end of the array-like is null... but I seem to be the only person who still does that.
But then try this on for size:
function nodeWalkCells(e, callback) {
if (e = e.firstElementChild) do {
callback(e);
} while (e = e.nextElementSibling);
}
Whilst yes, it's more code, this one runs way faster, because JavaScript array-likes are always slow since they aren't true arrays, they're pointered lists that to index into them, you have to iterate past every single entry BEFORE the one you're looking for each and every access! Going to the DOM structure to find the first one then loop through all the siblings cuts out that middle-man.
Same with this obsession with Array.forEach and Object.forEach, particularly with arrow functions we've been seeing. It's C style thinking that forgets the fact you just introduced function overhead AND extra stack assignment to the equation. They are not saving you any real code worth mention, they are not making the resultant code any clearer, etc, etc, etc...
I keep seeing people operate on objects thusly:
Object.keys(this).forEach(key => {
const value = this[key];
});
Which is more cryptic, slower, induces memory thrashing with the block level stack release, and is actually more code!
for (var key in this) {
var value = this[key];
In fact because the variables aren't locked / released at the block scope, it means LESS stack thrashing since you only allocate as needed (or even better lifting turns it into forward declaration) and a single stack release. Turning that into x86 assembler means a simple "ret x" where x is the number of bytes allocated to function-local variable space on the stack.
But don't try to tell the ECMAScript 6 fanboys that... which like everything else hot, trendy, and steps backwards in mindset they have plenty of lame excuses for, that hold water like a steel sieve.
Basically though, you're thinking while{} because that's all you ever see in C syntax code. Not because there aren't better ways, but because the concepts of where and when to use them -- much less their existence -- simply isn't discussed. Just like how the condition operator in a for loop can accept ANY condition. Just like how "for/in" or "for/of" in most cases is superior in clarity to .foreach(->).
Either people don't know they exist because they've never seen it in a codebase, or avoid it out of unfounded fears made up by those who couldn't grasp them. (see the bizzaro claims about how "unreliable" for/in is.)
I'd suggest trying to avoid using while(true) and break -- it reeks of spaghetti code jump-style.
You could just do-while there. As someone weaned on assembly and pascal, the do/while (what Pascal calls repeat/until, and in ASM is the cornerstone of all efficient loops) structure is just closer to how the hardware works and feels more intuitive the lower-level you go. As a construct, while (true) is just a wasted boolean comparison in the loop.
do { myConsole.print('Take a guess: '); guess = parseInt(await myConsole.readln()); myConsole.println(guess.toString()); myConsole.println( guess > number ? 'My number is smaller!' : ( guess < number ? 'My number is greater!' : `Congratulations, ${playerName}! My random number is ${number}!` ) ); } while (guess !== number);Also, ternary operators are your friend. If every single result is just going to println, you only need one println.