Bug #15285
closedlambda return behavior regression from #14639
Description
The change in ea15ceddbef2cc4c459c1ad5796e43ae9fa2cbf1 to use rb_yield_force_blockarg changes the behavior of returns called inside a passed lambda function. In 2.5.1 and below, including before the enum.c change, the attached script would print true
. In 2.5.3 it prints false
.
Files
Updated by shyouhei (Shyouhei Urabe) almost 6 years ago
- Related to Bug #14639: Array#map and lambda arity regression added
Updated by shyouhei (Shyouhei Urabe) almost 6 years ago
ea15ceddbef2cc4c459c1ad5796e43ae9fa2cbf1 is r64996, which is a backport of r63030, which fixes #14639.
@nobu (Nobuyoshi Nakada) any idea?
Updated by jhawthorn (John Hawthorn) almost 6 years ago
I also ran into this problem in ruby 2.5.3.
This is a little confusing because there are two things being changed here:
- How arguments are handled in a passed &lambda, which was asked for in #14639
- How return is handled in a passed &lambda
I attached a test script to help demonstrate
In ruby 2.3, the passed lambda will always splat the arguments (the lambda treats arguments like a block), but return only returns from the lambda
2.3.7
Array#map
args ✅
return ✅ lambda return semantics
Enumerable#map
args ✅
return ✅ lambda return semantics
Array#each
args ✅
return ✅ lambda return semantics
Array#map!
args ✅
return ✅ lambda return semantics
In ruby 2.4, the passed lambda now treats arguments like a normal lambda (it won't splat them). I think this is a good change (but that could be a debate). This is the complaint in #14639
2.4.4
Array#map
args 💣 wrong number of arguments (given 1, expected 2)
return ✅ lambda return semantics
Enumerable#map
args 💣 wrong number of arguments (given 1, expected 2)
return ✅ lambda return semantics
Array#each
args 💣 wrong number of arguments (given 1, expected 2)
return ✅ lambda return semantics
Array#map!
args 💣 wrong number of arguments (given 1, expected 2)
return ✅ lambda return semantics
In ruby 2.5.3 and in 2.6.0-preview3, Array#map
was changed to always treat the passed lambda as a block. This changed both how it treats arguments (the desired change) and how it treats return (this bug).
In addition, it only made this change to Array#map
aka Array#collect
, which now doesn't match similar methods like Enumerable#map
or Array#each
or Array#map!
. It's also a weird behaviour to have since it would be hard to write a custom MyClass#map
in ruby which behaved the same way.
2.6.0
Array#map
args ✅
return ❌ block return semantics
Enumerable#map
args 💣 wrong number of arguments (given 1, expected 2)
return ✅ lambda return semantics
Array#each
args 💣 wrong number of arguments (given 1, expected 2)
return ✅ lambda return semantics
Array#map!
args 💣 wrong number of arguments (given 1, expected 2)
return ✅ lambda return semantics
I think both r64996 (for 2.5.x) and r63030 should be reverted.
Updated by nobu (Nobuyoshi Nakada) almost 6 years ago
- Status changed from Open to Closed
Applied in changeset trunk|r65923.
Revert r63030
- array.c (rb_ary_collect): no longer splat sole array for lambda.
[ruby-core:89734] [Bug #15285]