What are the differences between checking if block
I have a ruby method that needs to check if a block was passed to it. A colleague is suggesting that simply checking if block.nil?
is slightly faster in performance and works for named blocks. This is already quite annoying since he is using the named block and invoking it using block.call
rather than yield
which has been shown to be significantly faster, since named blocks are more easy 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 suggest that block_given?
is thread safe.
What are the main differences between the two approaches? Please help me prove him wrong!
First off, while a single nil?
check might be faster than block_given?
, capturing the block is slow. So unless you were going to capture it anyway, the performance argument is invalid.
Secondly, it's easier to understand. Whenever you see block_given?
, you know exactly what is up. When you have x.nil?
, you have to stop and think what x
is.
Thirdly, it's an idiom. In my experience, the overwhelming majority of Ruby developers will prefer block_given?
. When in Rome...
Lastly, you can keep it consistent. If you always use block_given?
the problem is solved for you. If you use nil?
checks, you have to have the block captured.
Enumerable#map
will get for example? nil?
checks can prove difficult. I think that the main difference is that block_given?
can be used without explicitly defining &block
in method definition:
def named_block
if !block_given?
puts "No block"
else
yield
end
end
Which version is better when it goes for readability? Sometimes explicitly naming the block can be more readable and sometimes yield
can be more readable. It's also mater of personal preferences.
When it goes to speed, in benchmarks, that you've included, the yield
is faster. That is because Ruby doesen't have to initialize new object ( Proc
) for the block and assign it to variable.
There is another way to accomplish 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 this too seriously
UPD : as noted by @Lukas in comments, it fails on the block, that raises an exception ⇒ FIXED
链接地址: http://www.djcxy.com/p/37226.html上一篇: Jenkinsfile中的动态参数?
下一篇: 检查块是否有区别