Nunchucks
Nunchucks

Reputation: 1230

Ruby - Is &prc different than &block?

I'm writing a simple method that adds num to the return value of the block that is passed to it and I noticed that &block and &prc both work. I know that a proc is an object and can be assigned to a variable which could be handy. Is that the only difference though? Is there any difference between these two when it comes to performance, convention, or versatility? Is it ever better to use &block instead of &prc?

def adder(num = 1, &block)
  yield + num
end

vs.

def adder(num = 1, &prc)
  yield + num
end

Upvotes: 1

Views: 586

Answers (3)

Roman Kiselenko
Roman Kiselenko

Reputation: 44360

Is there any difference between these two when it comes to performance, convention, or versatility?

There is no difference between these, you able to name it as you want, it's just a name. Some devs call it &blk some &block or &b or &foo ...

>> def foo &foo
>>   yield
>> end
=> :foo
>> foo do
?>   puts '1'
>> end
1

Strictly saying & is an operator which you can apply to any object, and it will take care of converting that object to a Proc by calling to_proc().

>> def bar(&some_proc)
>>   some_proc
>> end
=> :bar
>> p = bar { puts 'Call proc' }
=> #<Proc:0x005601e6d69c80@(irb):4>
>> p.call
=> Call proc
>> p.class
=> Proc

Only the one thing is important, the name should be informative.

Upvotes: 3

tadman
tadman

Reputation: 211560

Line any argument to your method the name is largely subjective. Typically you'll see &block used if only by convention, but the name itself can be anything you want so long as it's a valid variable name.

In your example you're declaring a block name but not actually using the name. Keep in mind that any Ruby method can be given a block, there's no way to restrict this, but it's up to the method itself to use the block if it wants. That block can be called zero or more times either immediately or at some point in the future. Giving the block to the method surrenders control, so be sure to read the documentation on any given method carefully. There can be surprises.

If you need to chain through a block, declare it with a name:

def passes_through(&block)
  [ 1, 2, 3, 4 ].each(&block)
end

If you are going to yield on the block there's no need here:

def direct_call
  [ 1, 2, 3, 4 ].each do |n|
    yield n
  end
end

If you're going to preserve the call and use it later, that's also a case for naming it:

def preserved_call(&block)
  @callback = block
end

def make_callback
  @callback and @callback.call
end

Any method can check if a block was supplied:

def tests_for_block
  if (block_given?)
    yield 'value'
  else
    'value'
  end
end

There's a small but measurable cost to capturing a block by declaring it in the method signature, a lot of computation has to be done to properly capture all the variables that might be used in a closure situation. In performance sensitive code you'll want to avoid this.

You can dynamically create a block:

def captures_conditionally
  if (block_given?)
    @callback = Proc.new
  end
end

The Proc.new method will assume control over whatever block has been supplied to the method if one has been.

Upvotes: 1

davidhu
davidhu

Reputation: 10434

in your example, there is not a difference between &block and &prc, because in each case you are just passing a block to be call into the method.

Block and proc are similar in that they are both blocks of code.

[1,2,3].each {|x| puts x }

everything within the {} is the block.

A proc is just a block of code that you can name and can be called at a later time.

put_element = Proc.new {|x| puts x}

then you use put_element as an argument in your function.

Upvotes: 0

Related Questions