From: larskanis@... Date: 2020-01-16T09:57:31+00:00 Subject: [ruby-core:96908] [Ruby master Feature#16499] define_method(non_lambda) should not change the semantics of the given Proc Issue #16499 has been updated by larskanis (Lars Kanis). Unfortunately `define_method` is currently the only way to retrieve `Proc#parameters` without information loss. See #15357 and [here](https://github.com/larskanis/eventbox/blob/3bcbc30096c6003e96d41c6496c781dfc90ac36a/lib/eventbox/argument_wrapper.rb#L10-L17) for the workaround per `default_method`. Therefore fixing `default_method` would also require fixing `Proc#parameters`. ---------------------------------------- Feature #16499: define_method(non_lambda) should not change the semantics of the given Proc https://bugs.ruby-lang.org/issues/16499#change-83926 * Author: Eregon (Benoit Daloze) * Status: Rejected * Priority: Normal * Assignee: * Target version: ---------------------------------------- From https://bugs.ruby-lang.org/issues/15973?next_issue_id=15948&prev_issue_id=15975#note-38 But I think we should change `define_method(&non_lambda)` because that currently confusingly treats the same block body differently (e.g., the same `return` in the code means something different). This is the only construct in Ruby that can change a non-lambda to a lambda, and it's very inconsistent. It also forces implementations to have a way to convert a proc to a lambda, which is a non-trivial change. We could maybe make `define_method(name, non_lambda)` just wrap the Proc in a lambda, automatically, just like we can do manually with: `define_method(name, -> *args { non_lambda.call(*args) })`. But it would also preserve `arity`, `parameters`, etc. Then it wouldn't be any more verbose, but it would avoid the problem of treating the same `return`/`break` in the code differently. My point is we shall never change the semantics of `return`/`break` somewhere in the code. It should always mean exactly one thing. `define_method(name) { literal block }` is fine with that rule, it always behave as a lambda. But `define_method(&non_lambda)` is problematic as `non_lambda` can be passed to other methods or called directly. I believe exactly 0 people want `foo { return 42 }` to change its meaning based on whether `foo` calls `define_method` or not. OTOH, it seems people have repeatedly wanted to convert a proc to a lambda, but for other reasons. We should look at those reasons and provide better alternatives. I think sometimes people want to know how many arguments a non-lambda Proc takes. For example, `proc { |a,b=1| }`. `proc.arity` gives `1` here which might be helpful but also surprising as that Proc accepts any number of arguments. They might also look at `proc.parameters` which gives `[[:opt, :a], [:opt, :b]]` which does not differentiate `a` and `b` even though only `b` has a proper default value. `lambda { |a,b=1| }.parameters` returns the more useful `[[:req, :a], [:opt, :b]]`. Maybe we should return the same as for a lambda for `non_lambda.parameters`? `Proc#lambda?` would still tell whether it's strict about arguments and whether it deconstructs them. cc @zverok -- https://bugs.ruby-lang.org/ Unsubscribe: