Why does: respond_to?
in:
class Wolf
def howl; end
end
Wolf.new.respond_to?(:howl) # => true
not require &
while map
in:
["1", "2", "3"].map(&:to_i) # => [1, 2, 3]
does? Also, are there any technical names for this?
Why does: respond_to?
in:
class Wolf
def howl; end
end
Wolf.new.respond_to?(:howl) # => true
not require &
while map
in:
["1", "2", "3"].map(&:to_i) # => [1, 2, 3]
does? Also, are there any technical names for this?
When you say :method
, you're using some nice syntactical sugar in ruby that creates a new Symbol object. When you throw an ampersand before it (&:method
), you're using another piece of sugar. This invokes the to_proc
method on the symbol.
So, these two things are identical:
method_proc = &:method
sym = :method
method_proc = method.to_proc
What's the difference between that and the other usage? Well, respond_to?
has a single argument -- a symbol. So we can pass :method
and be all fine and dandy. (Interestingly, objects do respond to the method named method
, but that's a far more confusing question).
By comparison, Enumerable's iterators (like map
, select
, etc) accept a block. When we pass a Proc, it is interpreted properly as that block. So, these two pieces of code are equivalent:
[1,2,3].map { |i| i.even? }
[1,2,3].map(&:even?)
This equivalence is a little confusing, because of course Symbol has no idea that there's an even?
method somewhere. To play around with it, I used evenproc = :even?.to_proc
to inspect the resulting proc. It's implemented in C (at least in MRI ruby), and isn't willing to give up its source. However, its arity is -1
, which means that it accepts one optional arg. My best guess is that it does something like this:
def to_proc
method_name = self.to_s
->(a) { a.send(method_name) }
end
I could dig further, but I think we've already gone way past the question. ;) Good luck!