What is the difference between block_given validation? and! block.nil?

I have a ruby โ€‹โ€‹method that should check if a block has been passed. A colleague suggests to simply check if block.nil? slightly faster in performance and works for named blocks. This is already quite annoying, since it uses a named block and calls it using block.call , rather than yield , which has been shown to be significantly faster , since named blocks are easier to understand in terms of readability.

Version 1:

 def named_block &block if block.nil? puts "No block" else block.call end end 

Version 2:

 def named_block &block if !block_given? puts "No block" else block.call end end 

Benchmarking shows that version 1 is slightly faster than version 2, however a quick look at the source code seems to be block_given? safe stream.

What are the main differences between the two approaches? Please help me prove that he is wrong!

+7
performance ruby
source share
3 answers

First of all, although one check is nil? maybe faster than block_given? block grip is slow. Therefore, if you are not going to capture it anyway, the performance argument is not valid.

Secondly, it is easier to understand. Whenever you see block_given? , you know exactly what is going on. When do you have x.nil? , you need to stop and think about what x .

Thirdly, this is an idiom. In my experience, the vast majority of Ruby developers will prefer block_given? . When in Rome ...

Finally, you can keep it consistent. Should you always use block_given? , the problem is solved for you. Should you use nil? checks nil? You must block the block.

  • Performance overhead.
  • This is more detailed, something rubists try to avoid.
  • Naming things is one of the most difficult in programming. :) Can you think of a good name for the Enumerable#map block, for example, get it?
  • "Grepability" is a desirable feature for the codebase. If you want to find all the places where you are checking if a block has been provided to you, nil? execution nil? inspections can be difficult.
+4
source share

I think the main difference is that block_given? can be used without explicitly defining &block in a method definition:

 def named_block if !block_given? puts "No block" else yield end end 

Which version is better when it is suitable for reading? Sometimes an explicit block designation may be more readable, and sometimes yield may be more readable. It also depends on personal preference.

When it goes to speed, in the tests you included, yield is faster. This is because Ruby does not have to initialize a new object ( Proc ) for the block and assign it to a variable.

0
source share

There is another way to do this:

 def named_block (Proc.new rescue puts("No block") || ->{}).call end โ–ถ named_block #โ‡’ No block โ–ถ named_block { puts 'BLOCK!' } #โ‡’ BLOCK! 

please don't take it too seriously

UPD : as @Lukas noted in the comments, it does not work in the block, which raises an exception โ‡’ FIXED

-one
source share

All Articles