Project

General

Profile

Bug #15620

Block argument usage affects lambda semantic

Added by alanwu (Alan Wu) over 1 year ago. Updated 9 months ago.

Status:
Closed
Priority:
Normal
Target version:
-
ruby -v:
ruby 2.7.0dev (2019-11-12T17:29:13Z master a5448c46bd) [x86_64-darwin18]
[ruby-core:91616]

Description

The following snippet demonstrate the issue:

def pass_after_use(&block)
  raise unless block
  lambda(&block).call
end

def direct_pass(&block)
  lambda(&block).call
end

pass_after_use do |_arg|
  puts "fine, because block is materialized into a Proc before it is passed to #lambda"
end

direct_pass do |_arg|
  puts "Raises because all args are required. This is not printed"
end

Output:

fine, because block is materialized into a Proc before it is passed to #lambda
Traceback (most recent call last):
    2: from lambda-block-pass.rb:14:in `<main>'
    1: from lambda-block-pass.rb:7:in `direct_pass'
lambda-block-pass.rb:14:in `block in <main>': wrong number of arguments (given 0, expected 1) (ArgumentError)

I think having the line raise unless block affect Kenrel#lambda's semantic is pretty surprising. Note that if I do raise unless block_given?, call to the lambda without arg also raises.

If I was to decide, I would always have the resulting lambda have required arguments even after multiple levels of block pass. That is, as long as the original block is a literal block.

This is either a breaking change or a regression from 2.4. The same script executes without raising in 2.4.5 (block arguments are always materialized).


Related issues

Related to Ruby master - Feature #15973: Let Kernel#lambda always return a lambdaClosedmatz (Yukihiro Matsumoto)Actions

Also available in: Atom PDF