Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: Implicit Block Converted to Proc

My understanding is that a block implicitly attached to a method must be yielded; it cannot be called. So I'm trying to understand why this works:

def execute_code
  proc.call
end

execute_code { "Why does this work?" } # => "Why does this work?"

Attaching a block to this code executes successfully.

Any insight? I haven't found any documentation hinting that an implicit block is automatically converted to a proc object and assigned to the variable proc.

Ruby 2.5.3

like image 482
ljwhite Avatar asked Mar 01 '23 16:03

ljwhite


1 Answers

For Ruby 2.5.3, the docs for Kernel#proc() say:

Equivalent to Proc.new.

and the docs for Proc.new say:

Creates a new Proc object, bound to the current context. Proc::new may be called without a block only within a method with an attached block, in which case that block is converted to the Proc object.

which is what is happening in your example. You are calling proc in a method with a block, and the block is being converted to a Proc.

However this behaviour changes in later versions. If you try in Ruby 2.7,1 you will get a warning like this (although it will still work):

proc.rb:2: warning: Capturing the given block using Kernel#proc is deprecated; use `&block` instead

In Ruby 3, it won’t work at all (and in fact behaves as you seem to expect):

proc.rb:2:in `proc': tried to create Proc object without a block (ArgumentError)
    from proc.rb:2:in `execute_code'
    from proc.rb:5:in `<main>'

The docs for 3.0.0 are unchanged though. This looks like a bug in the docs (it has been fixed in master). It looks like this was first raised in the issue tracker in 2014 and then later in 2019.

like image 149
matt Avatar answered Mar 13 '23 02:03

matt