简体   繁体   中英

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?

Generally, you only use the &block argument if you need to pass the block to another method such as in this made 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 (ie 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.

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM