3 ms·
Except the over head of that loop is orders of magnitude higher than the reduction. Did you get the bounds right; what happens if you accidently start at 1 or e
by lordCarbonFiber 9y ago
Except the over head of that loop is orders of magnitude higher than the reduction. Did you get the bounds right; what happens if you accidently start at 1 or end at <=; what if you're nested; did you use i and j in the right place? The nooks for bugs in your "simple" loop are so profound that, in a language with expressive maps, I wouldn't accept that code in a review.
"Simple" is great until you're debugging off by one errors or any other errors between chair and keyboard. Complexity, in the sense that this guy rails against, is expressiveness. And, expressive code beats "simple" code every day of the week.
--Quick edit
Imagine that loop in assembly. It's objectively "less complex" yet you didn't express it that way. Why? I think the answer to that question is the heart of the positive argument for programming abstractions (and the "complexity" they bring).
- dvt 9y ago> Except the over head of that loop is orders of magnitude higher than the reduction. Except that it's not. Read the SO answer I linked. > The nooks for bugs in your "simple" loop are so profound that, in a language with expressive maps, I wouldn't accept that code in a review. Yep, I've definitely worked with people like you. With all due respect, I just think you're fundamentally wrong. Off-by-1 errors will happen no matter what, and even a rudimentary test suite can catch those.
- lordCarbonFiber 9y agoOff by one errors can't happen in the functional version. There's no reason to take a fatalist stance here. Just saying "well those programmers should write more tests" is silly when you could say, well why not tests and write code that is naturally hardened against foot guns. I was referring to mental overhead; though in a more modern language like rust the performance implications would be far less profound than the linked SO discussion.
- dvt 9y ago> Just saying "well those programmers should write more tests" is silly when you could say, well why not tests and write code that is naturally hardened against foot guns. I don't think off-by-1 errors are that big of a foot gun, compared to, like, having a null as part of the language, or pointers, or about a million other things. > I was referring to mental overhead Gotcha. I still think that "linear step-by-step" thinking like "you take stuff out of a bucket, and then do stuff to it" is easier to parse than map-reduce, which requires you to have a "big picture" view of the whole process.
- carussell 9y ago> Off by one errors can't happen in the functional version. No? Not only can they happen, but I'd argue that it's easier for them to occur when using `reduce`, because you have to remember the initializer. Omitting it has no effect in the given example, but the given example is contrived. It's not rare to be dealing with something more complex than a list of numbers, so let's try that instead. Let's say your items are a list of nodes. You want to sum their payloads to determine their aggregate cost. And, like jasonkostempski[1], you see `map` as superfluous. You've got this. You write: nodes.reduce((sum, x) => sum + x.value) Uh-oh. Now the fact that there is no initializer does affect the result. 1. https://news.ycombinator.com/item?id=15867033 https://news.ycombinator.com/item?id=15867033
- thethirdone 9y ago> No? Not only can they happen, but I'd argue that it's easier for them to occur when using `reduce`, because you have to remember the initializer. I would say that's not an off by one error. Its a similar scale and type of error, but not the same.
- dvt 9y agoIt's much more insidious than an off-by-one error in a for-loop - the initializer is hidden!
- spdionis 9y agoUnless you use a language that actually enforces you to pass required parameters to a function call.
- carussell 9y ago... which still wouldn't fix this problem, because the initializer is not a required parameter. It's allowed to be omitted by design, to signify that the first element shall be skipped and never passed as the second arg to the callback—or to put it another way, instead of being called once for each element, it's meant to handle the gaps between elements.
- goialoq 9y agoWhy have a compiler at all if you want to defer all error-checking to runtime?
- RandomInteger4 9y agoWhy does a programmer need to know an index counter exists if the index counter isn't used inside the for loop?