foo
foo

Reputation: 195

Does `block_given?` render `&block` parameter optional?

I am comfortable with the following:

def some_def(foo, &block)
    puts "block utilized below"
    block.call(foo)
end

def some_other_def(bar)
    puts "using yield below"
    yield bar
    puts "and back into the method"
end

So I have learned to keep blocks (and procs) separate from the yield keyword.

However, I ran into the following code:

# ./open_file.rb

class File
    def self.open(name, mode, &block)
        file = new(name, mode)
        return file unless block_given?
        yield(file)
    ensure
        file.close
    end
end

It seems the parameter &block does not matter when I implement execute this code in irb:

irb -r ./file.open.rb

and do something like:

File.open('foo.txt','r') {|f| puts f}

Is &block rendered optional by block_given? in:

return file unless block_given?

Upvotes: 2

Views: 1244

Answers (2)

mu is too short
mu is too short

Reputation: 434635

Generally, you only use the &block argument if you need to pass the block to another method such as in this made up example:

def m(&block)
  some_array.map(&block)
end

or this real version of Enumerable#sum from Rails:

def sum(identity = nil, &block)
  if block_given?
    map(&block).sum(identity)
  else
    sum = identity ? inject(identity, :+) : inject(:+)
    sum || identity || 0
  end
end

In either case, the block that the method is called with is used with another method call so you need a way to refer to the block (i.e. a name).

So block_given?/yield and &block serve different purposes. Being able to call block_given? doesn't make &block redundant and, as in the #sum implementation above, they can even be used together.

Upvotes: 5

sawa
sawa

Reputation: 168081

The &block in the method signature accepts a block, converts it into a proc, and assigns it to a variable named block. In case a block is not provided, block is assigned nil.

Whether to use the argument block within the method definition does not matter just like it does not matter whether an ordinary method argument bar is used or not in the following definition:

def foo(bar); end

However, accepting a block as a parameter and not using it is redundant and waste of resource. It may perhaps still make sense to explicitly indicate to a fellow programmer that the method accepts a block.

Using block_given? is independent of all this. It is independent of whether a block has been accepted as an argument via &. It refers to the block directly, irrespective of block.

Upvotes: 1

Related Questions