From: Christopher Dicely Date: 2009-03-22T17:16:25+09:00 Subject: Re: Passing a named function instead of a code block? On 3/21/09, 7stud -- wrote: > James Coglan wrote: >> 2009/3/20 7stud -- >> >>> >> &method(:square1) >>> > grab a method as an object without calling it, we need to use >>> preceded by some symbol. >> Yes, it probably looks that way. To see the difference it helps to know >> how >> Ruby is parsed. :square1 is an atomic unit representing the symbol whose >> name is 'square1'. ":" is not an operator, it is part of the syntax for >> symbols. However, "&" is an operator responsible for casting between >> procs >> and blocks. The expression '&square1' should be read '&( square1 )', >> that is >> we call square1 and cast the result of that using '&'. The same applies >> to >> 'method'. 'method' is a method that takes a symbol/string and returns >> the >> Method object with that name in the current scope. 'method(square1)' >> would >> be interpreted as a call to square1, passing the result to 'method'. >> >> So, '&square1' throws an error because you're calling a method with >> insufficient arguments. '&:square1' would try to cast a symbol to a >> proc, >> which if you're using ActiveSupport would return the block { |object| >> object.square1 }. >> >> '&square2' is fine as square2 is just a variable referring to a proc. >> Likewise, '&method(:square1)' is fine because method(:square1) is a >> Method >> object, which can be cast to a block. > > Thanks for the explanation. You said that (&) casts between block and > Procs. But (&) also appears to be casting a Method to a block in this > line: > > puts c.collect(&method(:fib)) Actually, its casting a Method to a Proc (by calling to_proc on it) and then treating the proc as a block. To see that's what is happening, try this: class Integer def to_proc Proc.new { self } end end (1..10).map(&1) > Can (&) cast a block to a Method? No. & in a method call always treats a the given proc as a block given to the method while & in a method definition always makes a block given to the method as a Proc. Its probably best not to think of this as "casting" except insofar as the first one "casts" to a proc first by calling to_proc; blocks aren't objects, and if you do this: def consume(object=nil) if block_given? then yield else object end end p = lambda { puts "foo!" } consume(&p) You don't get the results you' d get if an object of the (non-existent) class "Block" was passed to consume, you get the results you would get if consume was called with a block. So thinking of & as "casting" an argument to a different class in the method call is misleading.