Skip to content
Tags

,

Uniary ampersand operator

January 5, 2012

&object is evaluated in the following way:

1. if object is a block it converts the block to a simple proc.

ruby-1.9.2-p290 :074 > & do
ruby-1.9.2-p290 :075 > puts "Hello"
ruby-1.9.2-p290 :076?> end
SyntaxError: (irb):74: syntax error, unexpected tAMPER
(irb):76: syntax error, unexpected keyword_end, expecting $end
from /Users/gagan/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>'

ruby-1.9.2-p290 :081 > def test &block
ruby-1.9.2-p290 :082?> puts block.class
ruby-1.9.2-p290 :083?> block.call
ruby-1.9.2-p290 :084?> end
=> nil
ruby-1.9.2-p290 :085 > test {puts "hello"}
Proc
hello
=> nil
ruby-1.9.2-p290 :086 >

Note when using &block in a method definition, not only does it convert the block to a simple proc, but it also seems to be the only way to refer explicitly to the block as an argument. if the ampersand is removed, the argument block does not get the block passed to it. this is because blocks cannot be passed to a variable, procs can.

2. If object is a Proc, it converts the object into a block while preserving the lambda? status of the object.

ruby-1.9.2-p290 :094 > [1, 2, 3].map {|x| x + 5}
=> [6, 7, 8]
ruby-1.9.2-p290 :095 > offset = lambda {|x| x + 5}
=> #<Proc:0x00000101819be0@(irb):95 (lambda)>
ruby-1.9.2-p290 :096 > [1, 2, 3].map(offset)
ArgumentError: wrong number of arguments(1 for 0)
from (irb):96:in `map'
from (irb):96
from /Users/gagan/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>'
ruby-1.9.2-p290 :097 > [1, 2, 3].map {offset}
=> [#<Proc:0x00000101819be0@(irb):95 (lambda)>, #<Proc:0x00000101819be0@(irb):95 (lambda)>, #<Proc:0x00000101819be0@(irb):95 (lambda)>]
ruby-1.9.2-p290 :098 > [1, 2, 3].map {&offset}
SyntaxError: (irb):98: syntax error, unexpected tAMPER
[1, 2, 3].map {&offset}
^
from /Users/gagan/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>'
ruby-1.9.2-p290 :099 > [1, 2, 3].map(&offset)
=> [6, 7, 8]

It seems that the ‘conversion to block’ is shown by the fact that .map doesn’t just return an enumerator or complain, but executes as though the block was passed to it, as it would happen here:

ruby-1.9.2-p290 :110 > def test
ruby-1.9.2-p290 :111?> yield
ruby-1.9.2-p290 :112?> end
=> nil

ruby-1.9.2-p290 :114 > test {puts "hi"}
hi
=> nil

ruby-1.9.2-p290 :113 > test lambda{ puts "hi"}
ArgumentError: wrong number of arguments (1 for 0)
from (irb):110:in `test'
from (irb):113
from /Users/gagan/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>'

(note: I do not appreciate this completely… especially the maintenance of the lambda? part)

3. If object is not a Proc or a block, it first calls #to_proc on the object and then converts it into a block

ruby-1.9.2-p290 :104 > "1".to_i
=> 1
ruby-1.9.2-p290 :105 > :to_i.to_proc.call "1"
=> 1

ruby-1.9.2-p290 :115 > ["1", "2", "3"].map {|x| x.to_i}
=> [1, 2, 3]
ruby-1.9.2-p290 :116 > ["1", "2", "3"].map(&:to_i)
=> [1, 2, 3]

ref: http://ablogaboutcode.com/2012/01/04/the-ampersand-operator-in-ruby/

Advertisements

From → Uncategorized

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: