7 ms·
I legitimately cannot spot the bug. Can you write out the equivalent Ruby code in Go pre-generics? I really did try but I honestly cannot understand what your R
by pipe_connector 5y ago
I legitimately cannot spot the bug. Can you write out the equivalent Ruby code in Go pre-generics? I really did try but I honestly cannot understand what your Ruby code is supposed to do. I don't know what select and take are supposed to do, and I can guess at reduce but the symbols in the method are utterly arcane to me. Does Take grab exactly 20 items or does it do something like nums[:21]? Depending on how Take is implemented it could be an off-by-one error in your loop? Usually in this case I'd check for equality instead; that's the only thing that looks off to me in your Go code.
In my opinion the Go code is dead simple and unambiguous with no nuance hidden away in methods whose exact semantics I certainly don't have memorized. I'd have to look at 3 different function signatures to figure out what those Ruby methods do every single time I was reviewing code like this.
- stouset 5y agoThe code is equivalent, except the golang version accidentally loops an extra time. `&:meth` is just Ruby syntax for "a function that calls the `meth` method on its argument". So `&:foo` is shorthand for `func(x) { x.foo }`. `take(n)` just returns the first `n` elements. `select(fn)` iterates for every element for which the function passed to it returns true. `reduce(fn)` combines the previous iteration with the result of calling the provided function on the next iteration. Thus `take(20)` gets the first 20 elements, `select(&:odd?)` iterates over every odd value in what's left, and `reduce(&:+)` adds every remaining element together. > In my opinion the Go code is dead simple and unambiguous with no nuance hidden away in methods whose exact semantics I certainly don't have memorized. These functions and Ruby's `&` syntax took a few sentences to explain. They are fundamentally not that complicated, although nobody would expect you to understand what they did before you've seen them just like any other function call. You didn't know what they do, which is fine. But now you do, and it is completely normal for people to assume that you should be capable of working with them in the same way that someone would expect you to write 2 * 5 instead of writing 2 + 2 + 2 + 2 + 2. Writing the full `for` loop in my example is the equivalent of the latter, with the equivalent pitfall that it's really easy to accidentally write an extra sixth addition when you only meant to put five of them. > In my opinion the Go code is dead simple and unambiguous with no nuance hidden away in methods whose exact semantics I certainly don't have memorized. I'd have to look at 3 different function signatures to figure out what those Ruby methods do every single time I was reviewing code like this. No, you wouldn't, for the exact same reason you don't look up the documentation for `for` or `range` or `if` or `*` every time you use them. They are simple, straightforward abstractions that any programmer will have more or less fully internalized given fifteen minutes of playing around with them, and which you will likely use multiple times a day in any language that supports them. I can assure you that bordering on 0% of programmers who regularly use languages with these functions did not understand the example. There was a time when I, too, did not know what to make of functions like these. I saw someone write a similar comment and I thought "that's totally inscrutable". And then I learned what those functions do and I now use them almost literally every single day. They are amongst the most useful and universal abstractions I have ever come across.
- pipe_connector 5y agoI think you overestimate my ability. I've spent > 10 years programming in languages that have features like this (take and select excluded I think? Or maybe they had different names?) and I've just never internalized functions that are generic like this. Usually what I end up doing is opening up a REPL or making a toy program so I can iteratively see what happens to the collection. This probably makes me a bad programmer but I'm just being honest: It's too much cognitive overhead for me when I'm trying to spend the rest of my brain power on keeping track of the actual problem I want to solve -- which usually means interpreting code written by 30 other engineers over long period of time (read: it's a mess). I was reflecting on this and the one language where I don't feel this way is SQL. I'd consider it my strongest language, and it's an extremely functional language. I have no trouble deciphering complex SQL, but it takes me an enormous amount of time to figure out what happens in those long function chains in general purpose programming languages. I'm not sure what it is about SQL that makes me feel this way, but maybe it gives some hint why our brains seem to work in different ways?
- stouset 5y agoI think you underestimate your ability. As a programmer, you've already learned and internalized abstractions that are far more complicated than anything here. `select` is often aliased to `find_all` and that's what it does: finds all elements matching what's passed to it. `take` is sometimes aliased to `first`. Expanded ever so slightly: nums.first(20).find_all { |n| n.odd? }.reduce { |sum, n| sum + n } This reads: take the first twenty elements, find all the ones that are odd, and reduce by adding them together. The only "clunky" bit here is the word "reduce" which IMO there isn't an equivalent common English word for that gives a good intuition for what it does. It might not look like it if you haven't internalized these abstractions, but they reduce cognitive load. Dramatically. You don't have to read through a complicated set of conditionals and control flow statements in an explicit loop, you can read the bits entirely linearly and (almost) in straight English. Once comfortable with these, you can quickly glance at pretty much any expression like this and know immediately both what it does and have extreme confidence it doesn't contain bugs, because there just isn't anywhere for bugs to be. Don't sell yourself short. Take the time to learn these, and you will be a better programmer for it.