Last active
November 3, 2021 08:59
-
-
Save mudge/786953 to your computer and use it in GitHub Desktop.
How to pass blocks between methods in Ruby < 3.0.0 without using &block arguments.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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) |
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.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@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 withblock_given?
before callingProc.new
in that situation.