2

I often write:

some_array.each { |array_element| array_element.some_method(args) }

Why not have an option for an implicit yield so you could write e.g.:

some_array.each { _.some_method(args) }

I am not sure what character _ should actually be, and I imagine it would only be used in the most boilerplate setting, where you're dealing with a one-dimensional array and just trying to yield each item to the block in succession. It would save a lot of redundant typing.

sawa
  • 165,429
  • 45
  • 277
  • 381
the911s
  • 1,824
  • 17
  • 17
  • Interesting idea. That implementation would be a problem, but that's a detail: `class A; def a; puts 'hi'; end; end`, `_ = A.new`, _.a #=> hi`. – Cary Swoveland Nov 03 '14 at 07:15

1 Answers1

2

Are you familiar with #to_proc and the & syntax for method calls? They cover some cases similar to the one you show here. For example:

[1, -2, -4].map(&:abs) => [1, 2, 4]

The & is used to pass an object in place of a block. If the object isn't a Proc, #to_proc is automatically called on it to get a Proc before it is used in place of the block. Symbol#to_proc returns a Proc which behaves like: { |obj, *args| obj.symbol_name(*args) }.

In your example, you use args which are presumably captured from the surrounding lexical environment. Symbol#to_proc won't help you there. But it wouldn't be hard to make a new Proc-building method which would. For example:

class Symbol
  def with_args(*args)
    Proc.new { |x| x.send(self, *args) }
  end
end

Then you could do:

some_array.each(&:some_method.with_args(args))

Whether that is any better than an explicit block is up to you. In any case, this is a technique you should be aware of.

Alex D
  • 29,755
  • 7
  • 80
  • 126