Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Purpose of & (ampersand) in Ruby for procs and calling methods

Tags:

I've noticed that a lot of examples dealing with Ruby Procs have the following & symbol in it.

# Ruby Example shout = Proc.new { puts 'Yolo!' }  def shout_n_times(n, &callback)   n.times do     callback.call   end end  shout_n_times(3, &shout) # prints 'Yolo!' 3 times 

My question is what is the functional purpose behind the & symbol? It seems that if I wrote the same exact code without &, it works as expected:

# Same code as previous without & shout = Proc.new { puts 'Yolo!' }  def shout_n_times(n, callback)   n.times do     callback.call   end end  shout_n_times(3, shout) # prints 'Yolo!' 3 times 
like image 398
wmock Avatar asked Feb 10 '15 19:02

wmock


People also ask

What was the meaning of purpose?

1a : something set up as an object or end to be attained : intention. b : resolution, determination. 2 : a subject under discussion or an action in course of execution. on purpose. : by intent : intentionally.

What is an example of purpose?

Purpose is defined as to plan or intend to do something. An example of purpose is someone deciding they will start saving 10% of their income. An object to be reached; a target; an aim; a goal. A result that is desired; an intention.

Is it the purpose for or the purpose of?

The "purpose of" a shoe is protecting your feet. A possible "purpose for" a shoe is to smash bugs. So "purpose of" describes a property or capacity of a shoe, where "purpose for" describes what might be done with a shoe.

What is the purpose or use?

Purpose of Use means the purposes and scope described in the Documentation (there called “intended use”), limited to uses in connection with radiation therapy planning and delivery, as patient quality assurance, treatment plan adaptation, machine quality assurance, machine commissioning and services for the Licensee.


2 Answers

This article provides a good overview of the differences.

To summarize the article, Ruby allows implicit and explicit blocks. Moreover, Ruby has block, proc and lambda.

When you call

def foo(block) end 

block is just a simple argument of the method. The argument is referenced in the variable block, and how you interact with it depends on the type of object you pass.

def foo(one, block, two)   p one   p block.call   p two end  foo(1, 2, 3) 1 NoMethodError: undefined method `call' for 2:Fixnum     from (irb):3:in `foo'     from (irb):6     from /Users/weppos/.rvm/rubies/ruby-2.1.5/bin/irb:11:in `<main>'  foo(1, Proc.new { 1 + 1 }, 3) 1 2 3 

But when you use the ampersand & in the method definition, the block assumes a different meaning. You are explicitly defining a method to accept a block. And other rules will apply (such as no more than one block per method).

def foo(one, two, &block)   p one   p block.call   p two end 

First of all, being a block, the method signature now accepts "two parameters and a block", not "three parameters".

foo(1, 2, Proc.new { "from the proc" }) ArgumentError: wrong number of arguments (3 for 2)     from (irb):7:in `foo'     from (irb):12     from /Users/weppos/.rvm/rubies/ruby-2.1.5/bin/irb:11:in `<main>' 

That means, you have to force the third argument to be a block passing the parameter with the ampersand.

foo(1, 2, &Proc.new { "from the proc" }) 1 "from the proc" 2 

However, this is a very uncommon syntax. In Ruby, methods with blocks are generally called using {}

foo(1, 2) { "from the block" } 1 "from the block" 2 

or do end.

foo(1, 2) do   "from the block" end 1 "from the block" 2 

Let's jump back to the method definition. I previously mentioned that the following code is an explicit block declaration.

def foo(one, two, &block)   block.call end 

Methods can implicitly accept a block. Implicit blocks are called with yield.

def foo(one, two)   p yield end  foo(1, 2) { "from the block" } 

You can check the block is passed using block_given?

def foo(one, two)   if block_given?     p yield   else     p "No block given"   end end  foo(1, 2) { "from the block" }  => "from the block"  foo(1, 2)  => "No block given" 

These block-related features would not be available if you declare the "block" as a simple argument (hence without ampersand), because it would just be an anonimous method argument.

like image 130
Simone Carletti Avatar answered Mar 06 '23 07:03

Simone Carletti


As supplementary, I make myself remember & as a conversion sign between block and Proc.

To convert a block to Proc

def foo(&p)   puts p.class end  foo {} # => Proc 

To convert a Proc to a block

def bar   yield "hello" end p = Proc.new {|a| puts a }  bar &p # => hello 
like image 23
ifyouseewendy Avatar answered Mar 06 '23 06:03

ifyouseewendy