Tuesday, May 22, 2012

What does the & mean in ruby?

The unary ampersand operator converts a block to a proc and a proc to a block. There are some functions, such as Array.map, which expect to be passed a block. You can pass these functions a proc instead with the & operator.


For example, say you have square = lambda {|x| x*x}. You can they write [1,2,3].map(&square), and that will return an array with elements 1, 4, and 9.


Conversely, you can use the & operator to pass a block where a proc would usually be required. Consider this function:


def apply_proc arg, &process
process.call(arg)
end


You can then say apply_proc('hello') {|x| puts x}, and it will work as expected: it will print hello. Important: parentheses are REQUIRED here. If you were just to say apply_proc 'hello' {|x| puts x} or apply_proc 'hello', {|x| puts x}, it would SyntaxError, because ruby would be unable to determine that the block was supposed to be the last argument (which seems to me to be kind of backwards, but that's how it is). Also, you cant have a function definition like def apply_proc &process, arg, because a block can only be passed as the last argument of the function. This also means, or course, that you can only pass one block to a function. If only blocks were first class objects.


One more thing, on how things are actually converted in ruby. When ruby sees an & sign, it checks to see if the operand of the & is a proc, and if it is not, it converts it to a proc before converting it to a block using the .to_proc method. In ruby 1.9, the & operator works with symbols - &:capitalize gives you the string method capitalize. You HAVE to be careful of this, though. :capitalize.to_proc.call('hello') functions exactly the same as 'hello'.capitalize - the symbol to_proc method accepts an argument and calls "itself" on that argument. AND, as if you weren't already confused enough, you CAN'T say &:capitalize.call('hello'), you can only pass a proc to a function with an ampersand notation, as in apply_proc('hello', &:capitalize). This is incredibly confusing and absurd to me, because the symbol is not a block, as it would seem that it should be. But at any rate, ruby is confusing.


So that's what the & means in ruby.

No comments:

Post a Comment