Ruby: Implicit Block Converted to Proc

Viewed 369

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

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.

Related