-
-
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