I don't usually get drawn into this, but I have an answer to this because I've seen something similar in production.
jbverschoor said (edited for brevity):
> Yes. But you’re not expressing what you mean.
> It’s like doing a
> for(i=0; i<items.length:i++)
> { e=items[i] }
> to iterate over each element instead of something like foreach ...
haswell replied:
> How is that for loop not expressing what it means?
It's true that the for loop is accomplishing the goal, but it is specifically running through the elements from 0 to length.
But sometimes what you want to do is, for example, apply a function to every element, and the fact that they are in a structure indexed from 0 to N-1 is not relevant. Your intent is to do a thing for every element, not to run down a list doing the thing.
There is a difference in intent, and using foreach instead of a for loop quite specifically expresses that.
Small examples like this are never convincing, but there really is a difference between "Run down this list" and "do this thing for every element". The output is the same, but the intent is different, and expressing that intent is important in larger projects.
That intent is implicit, and using for or forEach does not by itself provide enough information about intent. I agree that using one vs. the other can be a strong hint. The surrounding code provides the rest of the story.
It may be true that running from 0…length is not the most important part, but it may also be true that I need more flexibility and control while iterating, and may still choose to use for as a result.
But I think we’re getting a bit off track (and I helped get us here…).
jbverschoor‘s comment was a followup about the expressiveness of the modulo operator vs built-in convenience methods.
At least in the case of JavaScript, there isn’t an isEven available. If it was, an argument could be made that using it is more expressive. Since it doesn’t, the argument can be made that the most expressive option is the idiomatic one. Certain code fragments become idiomatic for a reason.
I interpreted the comments about for and the perceived lack of expressiveness in using it against this backdrop, and my point was just that for still has a time and a place. It may be that jbverschoor recognizes this, but I think the comparison doesn’t quite help when examining the use of modulo.
I suspect we are largely in agreement. The example is not necessarily a good one, but I think we agree that the intent expressed by "foreach" is different from the intent expressed by "for ()", and while that difference might not matter, and might not be large, and might be carried equally by the context, it is real.
Going back to the original, there is a difference between "isEven(n)" and "0==n%2". Sometimes (and this is definitely true in some code I write) there is a conceptual difference between asking if something is even, versus asking if it leaves a remainder of 0 upon division by 2. Yes, they can be proven to be equivalent, but the underlying intent is different.
BTW, I agree entirely that in these cases it's really mostly pointless, but the principle carries over to larger examples. Trying to see that there is a difference is probably worth it, even if we agree that it doesn't really matter in these trivial cases.
Oh, and for a compiler I used to use it really did matter that you used "foreach" when you could, versus using "for ()", because it could dispatch things in parallel in the former case, and couldn't in the latter. So expressing the intent in the code itself and not just in the context really can matter.
The only nit I'll pick is re: the 2nd paragraph. I do agree that there is a difference in the expressions "isEven(n)" and "0==n%2" in isolation. But these expressions will always be surrounded by more code, and the degree of difference will entirely depend on that code and its structure. All of this can be very simply solved with a quick:
function isEven(n) { return 0==n%2 }
And let isEven = 0 == n % 2 provides about as much context as isEven(n).
Admittedly, I had to be conscious of how I wrote that expression, but choosing meaningful variable names is also just part of writing code, and isEven() by itself likely doesn't provide enough context about why I'm checking for even-ness to begin with. These considerations all need to go into the design of the class/method, but at no point can the developer wash their hands of the need to provide context through standard practices, just because the standard library provided more descriptive methods.
And I'm not saying this is what you're saying, but the original comment seemed to believe that more expansive standard libraries are somehow inherently better. I'd argue they're just different, and more factors to consider when choosing a language. Sometimes they help. Sometimes they're not worth the price of admission.
I think the discussion could be generalized as: how far should standard libraries go? No matter how good that standard library is, at some point, I must apply the fundamental skill of adding context and structure to the code I write.
jbverschoor said (edited for brevity):
> Yes. But you’re not expressing what you mean.
> It’s like doing a
> to iterate over each element instead of something like foreach ...haswell replied:
> How is that for loop not expressing what it means?
It's true that the for loop is accomplishing the goal, but it is specifically running through the elements from 0 to length.
But sometimes what you want to do is, for example, apply a function to every element, and the fact that they are in a structure indexed from 0 to N-1 is not relevant. Your intent is to do a thing for every element, not to run down a list doing the thing.
There is a difference in intent, and using foreach instead of a for loop quite specifically expresses that.
Small examples like this are never convincing, but there really is a difference between "Run down this list" and "do this thing for every element". The output is the same, but the intent is different, and expressing that intent is important in larger projects.