From: "rits (First Last)" Date: 2013-08-04T06:23:58+09:00 Subject: [ruby-core:56363] [ruby-trunk - Bug #8693] lambda invoked by yield acts as a proc with respect to return Issue #8693 has been updated by rits (First Last). alexeymuranov (Alexey Muranov) wrote: > > I agree it would be nice if Matz clarified the issue. > > rits (First Last) wrote: > > > > This notion that & somehow extracts the block from the lambda "shell", throwing the lambda shell away is incorrect. > > If you mean that this is not how things work, apparently it is true. But for me it would be the most natural if "(({&}))" was converting a lambda/proc into a block, and "(({&p}))" in the end of the argument list was wrapping the block into a proc called "(({p}))". For me in fact it would be the only non-surprizing behavior. > > Consider this: > > def m *a > a.object_id > end > > a = [] > > a.object_id # => 2155500640 > m *a # => 2155435920 (different) > > This looks completely normal to me. * extracts individual elements and passes them individually, in fact the receiving method can then regroup the individual args in many different ways: irb(main):010:0> def m1(a, *args, b); [a, args, b] end; m1 *[1, 2, 3, 4] => [1, [2, 3], 4] the original array, by definition, is discarded, only the elements are passed, so this can't work any other way, whereas method(&proc_or_lamda) can theoretically works in both modes (keep and invoke the proc/lambda or "extract" and keep just the block). At a minimum it should be consistent. Currently it keeps and invokes the proc, but with hybrid proc/lambda semantics (argument checking of a lambda, return of a proc). The current behavior is bug regardless of which conceptual model you pick. As to which model is preferable, I suppose that's debatable. I like the current model of keeping and invoking the proc/lambda (with this bug fixed). More on that below. > > However, i am surprised with this: > > def m &p > p.object_id > end > > p = proc{} > > p.object_id # => 2154923560 > m &p # => 2154923560 (same) > blocks are not first class citizens in ruby, there's no block class or block objects, so conceptually it makes sense to think of blocks as a role (or slot). So the block role can be played a syntactic ruby block or by a proc. If you think of it as a role/slot then the proc does not need to be unwrapped into a block "object" and then re-wrapped, but merely assume the block role or be put into the block slot, and then looked up in the block slot. This model has implication for this bug, yield would check the block slot and if there's a proc there, simply invoke it. I think this is what actually happens (given the evidence I provided: lambda is retained, lambda arity is enforced). The only quirk is the "return" ---------------------------------------- Bug #8693: lambda invoked by yield acts as a proc with respect to return https://bugs.ruby-lang.org/issues/8693#change-40870 Author: rits (First Last) Status: Rejected Priority: Normal Assignee: Category: Target version: ruby -v: ruby 2.0.0p247 (2013-06-27) [x64-mingw32] Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN irb(main):004:0> def m1; yield end; def m2; m1 &->{return 0}; 1 end; m2 => 0 -- http://bugs.ruby-lang.org/