3 ms·
In practice, you wouldn't use |u| either. You'd use |user|. I would only allow single character variables if they are scoped entirely within one line of code. B
by grumple 3y ago
In practice, you wouldn't use |u| either. You'd use |user|. I would only allow single character variables if they are scoped entirely within one line of code. But even then, best practice is to use good variable names, so I'd still prefer `users.map{ |user| do_something(user) }` or whatever. I use the to_proc pattern for existing methods on the object like `users.map(&:email)`.
The only case where I've used a shorthand pattern like _1 is with regex matching where the matched groups are not named, so $1, $2, $3 refer to the first, second, third matched groups, etc. Having worked a lot with csvs (mentioned in an example), referencing the header (or creating one) has always been really valuable, using numbers is asking for trouble when the spec inevitably changes or when a dev wants to know if a script will work with some new file.
- jonahx 3y agoImo using "good variable names" in cases where that variable is effectively functioning as nothing more than a syntactically necessary placeholder for a point-free phrase is a clear (if well-intentioned) mistake. It makes the code noisy and verbose for no benefit. To take the exact example you gave, `users.map{ |u| do_something(u) }` is unambiguously better than `users.map{ |user| do_something(user) }`. What we really want is `users.map{ do_something }`. It is only happenstance that ruby allows this form for methods only via `users.map(&:some_method)`, and we are stuck with forced variable names when calling other functions. Still, we can reduce the boilerplate as much as possible, and this is the basic argument of the article. Also fine: `users.map{ |x| do_something(x) }` (the "x" as a conventional placeholder for the meaningless but syntactically necessary placeholder) and `users.map{ do_something(_1) }` (the _1 accomplishing the same thing). In either case, the "meaningful variable" is already there in the name "users" -- repeating it is mere stutter and detracts from, rather than enhancing, clarity. The exception (as you noted) would be a longer multiline block where repeating `user` can aid short term memory, especially if the block contains other local variables.
- deleted 3y ago[deleted]
- dragonwriter 3y ago> It is only happenstance that ruby allows this form for methods only via `users.map(&:some_method)`, and we are stuck with forced variable names when calling other functions. Not sure what you are trying to say here, because there are so much odd about this that it is hard to penetrate. First, & works on proc-able objects (those that are Procs or can be converted to them via #to_proc), not "methods", and what you show it being used with is a symbol, not a method. Symbol#to_proc on a symbol s produces a proc that is functionally something like: ->(*args, **kwargs) { args[0].send(s, args[1..-1, **kwargs] } While that's complicated, the upshot is that it creates a proc that calls the method whose name is the symbol & was applied to on its first argument, passing its remaining arguments as the arguments to the method. > What we really want is `users.map{ do_something }`. But if you want to pass a method on self, the only thing in Ruby that you can call like do_something(x), to map, you can do that without an expllcit block already, by using the Object#method method, which returns a Proc that is equivalent to calling the method: users.map &method(:do_something) And if you want to call a Proc object in a local variable called do_something to map (the closest thing to a "non-method function" that exists in Ruby), you can do that without an explicit block, even more concisely, because you don't have to convert it to a Proc first: users.map &do_something
- jonahx 3y agoSigh. Yes, I am aware of the technicalities you describe. I thought my point was clear without my needing to be pedantically accurate. In many languages (even in JS!) you can just map a function point-free, rather than having to introduce a variable just because syntax demands it, or worry about which syntax to use depending on if the "function" you're calling is a method on the object being mapped or something else. It's all noise. > you can do that without an expllcit block already, by using the Object#method method, which returns a Proc that is equivalent to calling the method: > users.map &method(:do_something) Again, I am aware, and the ugliness of that solution proves the point I was trying to make -- it is even worse than the block syntax with a variable.
- dragonwriter 3y ago> In many languages (even in JS!) you can just map a function point-free, Yes, in many languages, "functions" are a thing that exists. In Ruby, there is no such thing as a function. The concept does not exist. Which is why it is bizarre to talk about what you can and can't do with "functions" in Ruby, and to call kinds of different not-function things (including symbols, of all things) "functions" in that discussion. Its just applying language that makes no sense.
- psychoslave 3y ago>using "good variable names" in cases where that variable is effectively functioning as nothing more than a syntactically necessary placeholder for a point-free phrase is a clear (if well-intentioned) mistake. If variable names are well picked they provide guiding context hints that ease understanding. If you have only a terse pack of symbols, deciphering the code will be longer because you have to go trough more contextualization to understand where the code take place and what it actually operates over for which purpose.
- pawelduda 3y agoI find this too cluttered: `billing_subscriptions.each { |billing_subscription| billing_subscription.status = ACTIVE }` This reminds me a lot of using(&:blabla). I'd prefer it: `billing_subscriptions.each { |bs| bs.status = ACTIVE}` But don't mind me I'm just bikeshedding