-
-
Save mudge/786953 to your computer and use it in GitHub Desktop.
# UPDATE: The ability to call Proc.new without a block was removed in Ruby 3.0.0 | |
# See https://bugs.ruby-lang.org/issues/10499 for more information. | |
# So you might have heard that this is slow: | |
# | |
# def some_method(&block) | |
# block.call | |
# end | |
# | |
# Compared to: | |
# | |
# def some_method | |
# yield | |
# end | |
# | |
# But how can you pass a block from one method to another without | |
# using the &block argument? | |
# | |
# def some_method(&block) | |
# some_other_method(&block) | |
# end | |
# | |
# Behold! | |
def some_method | |
some_other_method(&Proc.new) | |
end | |
def some_other_method | |
puts yield * 2 | |
end | |
some_method { "Magic!" } | |
# => "Magic!Magic!" | |
# As mentioned by Aaron Patterson in his RubyConf X presentation | |
# "ZOMG WHY IS THIS CODE SO SLOW", this means that you can avoid the cost | |
# of instantiating a Proc object altogether if suitable. | |
def some_method | |
if block_given? | |
some_other_method(&Proc.new) | |
end | |
end | |
# The key to this is in Proc.new which will create a Proc object from the | |
# block passed to the current method when called without any arguments of | |
# its own. | |
# For more information, see the following: | |
# http://www.ruby-doc.org/core/classes/Proc.html#M000547 | |
# http://confreaks.net/videos/427-rubyconf2010-zomg-why-is-this-code-so-slow (at around 30:00) |
Interesting!
What if you have block as an optional argument? With &Proc.new it will raise, so here using &block is a must right?
For example:
some_other_method(arg1, arg2, &Proc.new)
And if you call some_method
without a block it still should execute.
@zauzaj I wrote about this in a bit more detail in "Passing Blocks in Ruby Without &block
" but, yes, you'd need to detect whether an optional block was passed with block_given?
before calling Proc.new
in that situation.
The code does not work with Ruby-3.0.1. The error is "tried to create Proc object without a block (ArgumentError)"
@kopylovvlad you're right, it looks like this was changed in Ruby 3.0.0 (see #10499 and #15554) but the documentation still describes the old behaviour though this also looks like it has been fixed.
I've added a comment to the gist to flag this change of behaviour.
Thanks Bro this save me a lot of troubles