From: ruby-core@... Date: 2019-03-07T16:27:49+00:00 Subject: [ruby-core:91711] [Ruby trunk Bug#15620] Block argument usage affects lambda semantic Issue #15620 has been updated by marcandre (Marc-Andre Lafortune). Eregon (Benoit Daloze) wrote: > `lambda(&proc{}).lambda?` returns false because I think the rule is: > once a Proc is created, it never changes its lambda-ness. Right. I was wondering why this is the "rule", what's the rationale. It makes `lambda(&...)` equivalent to `...to_proc` but less clear. I was thinking only in terms of parameter passing (in which case the rule feels counter productive), but there's also handling of `break` and `return` (in which case the rule makes more sense I guess, still not convinced). Note that the rule can be broken, for example with: ``` def transform_proc_into_lambda(&proc) o = Object.new o.singleton_class.define_method(:foo, &proc) o.method(:foo).to_proc end transform_proc_into_lambda{}.lambda? # => true ``` ---------------------------------------- Bug #15620: Block argument usage affects lambda semantic https://bugs.ruby-lang.org/issues/15620#change-76981 * Author: alanwu (Alan Wu) * Status: Open * Priority: Normal * Assignee: matz (Yukihiro Matsumoto) * Target version: * ruby -v: * Backport: 2.4: UNKNOWN, 2.5: UNKNOWN, 2.6: UNKNOWN ---------------------------------------- The following snippet demonstrate the issue: ``` ruby 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 `
' 1: from lambda-block-pass.rb:7:in `direct_pass' lambda-block-pass.rb:14:in `block in
': 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). -- https://bugs.ruby-lang.org/ Unsubscribe: