Colour me stupid, but in the article it gives this code as having some horrible hard to find bug:
String s = "";
for (int i = 0; i < args.length; i++) {
s += array[i];
}
Now, as soon as I looked at that I immediately thought "well, they're not putting anything in between the params when they concatenate them", e.g. I would expect to see:
s += array[i] + "\t";
(or a comma or newline instead of a tab)
My next thought was "what happens if there are no args?" E.g. args.length returns 0, and they try to access the first element in the list (due to heritage from c pointers we start counting at 0) which is the 'zeroth' one, which doesn't exist... it should throw an array out of bounds exception.
-----
The reason I ask, is that based on the comments, the people reading the blog think the problem is in the operator overloading. Are they expecting this iteration through the args list to sum the args, and then assign the sum to the string?
If so, then I don't see how the bug could remain undetected:
"it could take weeks to get a bug report, and weeks more to get a fix ready"
Whereas in the unlikey event that I'm right, I still don't see how it would be hard to fix?
Why are you looping over array, when you are checking over the bounds of args? Shouldn't it be
s += args[i];
Normally, you loop over the thing you're checking the bounds for.
The fact that this has been sitting on HN front page all day and there's no single, satisfactory answer (I mean, is this a satisfactory answer?) is to me a Key Failure of the for loop. For loops just don't capture very much in terms of semantics.
Why are we befuddled by what this piece of code does? You can get into stupid pedantry about what a closure is (yes, looking at the top comment here), and various other details, but that misses the point of the article, which is that for-loop are practically an anti-pattern.
As a community, we've long realized that functions like fold, filter and map are good things, better than our equivalent of the for-loop, which is recursing over the data-structure. You better have a solid reason to write your own pattern match over a list. In all my years of writing functional code, I've only once had to write a function that recursed over a list, and boy was it a regrettable function.
I see the comments here which argue about what a closure really is (and there is a lot of conflicting info out there. Even Douglas Crockford explains it differently than the comments I've seen on this article) when the point of the article is that for loop are an anti-pattern - exactly as you say.
This realization really hit home for me when I started using Clojure and kept trying to figure out how to do a for-loop. Once you wrap your head around map, reduce and filter, all of a sudden you realize how expressive a programming language really can be.
"E.g. args.length returns 0, and they try to access the first element in the list (due to heritage from c pointers we start counting at 0) which is the 'zeroth' one, which doesn't exist"
I'm not sure if you're making some subtle point here that I'm missing, but it is not the case that any of the elements of array will be accessed by that code if args.length is 0. If args.length is 0, then the exit condition (which is evaluated before entering the loop body for the first time) will be false, and the loop body will not be executed at all.
I've been trying to figure out what he was getting at, as well.
The original article, by Elliotte, seems to have updated the code snippet to:
'
String s = "";
for (int i = 0; i < args.length; i++) {
s += args[i];
}
'
I deduce from this that the error was in the copy/paste. The line that was supposed to be changed to 's+= args[i]' was accidentally left as 's+= array[i]'
As such, its a simple failure to replace all instances of 'array' in the pasted code, rather than anything to do with 'operator overloading', or even to do with checking if 'array[i]' was out of bounds - there is simply no variable 'array' supposed to be in that context.
I wish Turoff had been less obtuse about it, especially as the original Elliotte post seems to have been silently updated.
In the interest of being fair, it is (by internet standards) quite an old blog post, which was probably a bit of a toss off effort in the first place.
If 'the bug' is just a copy/paste problem of a variable that doesn't exist in that scope, then compilation will fail at that point, so again, I don't see how that could be the one that Turoff said would survive for weeks in the wild.
But, if the bug is a copy/paste of a variable that does exist in that scope, he's exactly correct that it could survive for weeks and be very difficult to actually track down (because of the sort of blindness to details that happens when you read "idioms" like this by visual pattern matching rather than actually reading the code).
I up voted you showed so wonderfully that forcing an fallible human to correctly specify the same thing twice can result in errors.
But I don't think errors are the biggest issue. The biggest issue is that this kind of stuff should be getting out of our way so we can focus on other things.
Parent didn't need the downmods - it's the same poster replying to himself with "what a noob". I was about to post this same answer till I saw this at the bottom of the replies.
It's okay. I continue to be baffled and amazed at what gets voted up and what gets voted down, usually it balances out, so if something gets unexpectedly voted down, something else will get unexpectedly voted up.
My next thought was "what happens if there are no args?" E.g. args.length returns 0, and they try to access the first element in the list (due to heritage from c pointers we start counting at 0) which is the 'zeroth' one, which doesn't exist... it should throw an array out of bounds exception.
-----
The reason I ask, is that based on the comments, the people reading the blog think the problem is in the operator overloading. Are they expecting this iteration through the args list to sum the args, and then assign the sum to the string?
If so, then I don't see how the bug could remain undetected:
"it could take weeks to get a bug report, and weeks more to get a fix ready"
Whereas in the unlikey event that I'm right, I still don't see how it would be hard to fix?
What am I missing?