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
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.
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.
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With