[ruby-core:120252] [Ruby master Bug#20955] Subtle differences with Proc#parameters for anonymous parameters

Issue #20955 has been reported by zverok (Victor Shepelev). ---------------------------------------- Bug #20955: Subtle differences with Proc#parameters for anonymous parameters https://bugs.ruby-lang.org/issues/20955 * Author: zverok (Victor Shepelev) * Status: Open * ruby -v: ruby 3.4.0dev (2024-12-15T13:36:38Z master 366fd9642f) +PRISM [x86_64-linux] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONTNEED ---------------------------------------- ```ruby p proc { |x| }.parameters #=> [[:opt, :x]] p lambda { |x| }.parameters #=> [[:req, :x]] p proc { _1 }.parameters #=> [[:opt, :_1]] p lambda { _1 }.parameters #=> [[:req, :_1]] p proc { it }.parameters #=> [[:opt, nil]] p lambda { it }.parameters #=> [[:req]] ``` Note the last pair; here are two small confusing problems: 1. For proc, unlike numbered parameters, the parameter name is `nil` (not `it`). This, though, can be justified to distinguish from `proc { |it| }` case 2. But also, `proc` has this `nil` for a parameter name, while `lambda` has not. I am not sure what the “most logical” thing to do here, but I believe that at least `proc { it }` and `lambda { it }` should be made consistent with each other. -- https://bugs.ruby-lang.org/

Issue #20955 has been updated by bkuhlmann (Brooke Kuhlmann). Good catch. I would expect the following behavor: ``` proc { it }.parameters #=> [[:opt, :it]] lambda { it }.parameters #=> [[:req, :it]] ``` This would be consistent with existing behavior as shown with the `x` and `_1` variables. Is there a reason why `it` would need to behave differently? ---------------------------------------- Bug #20955: Subtle differences with Proc#parameters for anonymous parameters https://bugs.ruby-lang.org/issues/20955#change-111027 * Author: zverok (Victor Shepelev) * Status: Open * ruby -v: ruby 3.4.0dev (2024-12-15T13:36:38Z master 366fd9642f) +PRISM [x86_64-linux] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONTNEED ---------------------------------------- ```ruby p proc { |x| }.parameters #=> [[:opt, :x]] p lambda { |x| }.parameters #=> [[:req, :x]] p proc { _1 }.parameters #=> [[:opt, :_1]] p lambda { _1 }.parameters #=> [[:req, :_1]] p proc { it }.parameters #=> [[:opt, nil]] p lambda { it }.parameters #=> [[:req]] ``` Note the last pair; here are two small confusing problems: 1. For proc, unlike numbered parameters, the parameter name is `nil` (not `it`). This, though, can be justified to distinguish from `proc { |it| }` case 2. But also, `proc` has this `nil` for a parameter name, while `lambda` has not. I am not sure what the “most logical” thing to do here, but I believe that at least `proc { it }` and `lambda { it }` should be made consistent with each other. -- https://bugs.ruby-lang.org/

Issue #20955 has been updated by zverok (Victor Shepelev). @bkuhlmann The only possible reason is not to confuse with this: ```ruby proc { |it| }.parameters # the parameter is literally named "it" ``` I am not sure it matters much, but maybe in somebody’s metaprogramming... I don’t remember seeing libraries in Ruby that changed behavior depending on parameter names (and changing it on parameter name `it` seems even less plausible), but theoretically, it _could_ happen. (The situation is unlike `_1`, which is NOT allowed to be an explicit parameter name.) ---------------------------------------- Bug #20955: Subtle differences with Proc#parameters for anonymous parameters https://bugs.ruby-lang.org/issues/20955#change-111028 * Author: zverok (Victor Shepelev) * Status: Open * ruby -v: ruby 3.4.0dev (2024-12-15T13:36:38Z master 366fd9642f) +PRISM [x86_64-linux] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONTNEED ---------------------------------------- ```ruby p proc { |x| }.parameters #=> [[:opt, :x]] p lambda { |x| }.parameters #=> [[:req, :x]] p proc { _1 }.parameters #=> [[:opt, :_1]] p lambda { _1 }.parameters #=> [[:req, :_1]] p proc { it }.parameters #=> [[:opt, nil]] p lambda { it }.parameters #=> [[:req]] ``` Note the last pair; here are two small confusing problems: 1. For proc, unlike numbered parameters, the parameter name is `nil` (not `it`). This, though, can be justified to distinguish from `proc { |it| }` case 2. But also, `proc` has this `nil` for a parameter name, while `lambda` has not. I am not sure what the “most logical” thing to do here, but I believe that at least `proc { it }` and `lambda { it }` should be made consistent with each other. -- https://bugs.ruby-lang.org/

Issue #20955 has been updated by bkuhlmann (Brooke Kuhlmann). @zverok Makes sense...but this behavior would be nice (again, thinking in terms of consistency): ``` ruby proc { |_1| }.parameters # _1 is reserved for numbered parameter (SyntaxError) proc { |it| }.parameters # it is a reserved block parameter (SyntaxError) ``` _I realize this would break backwards compatibility in terms of semantic versioning, though._ That said, I can provide an example of `it` -- as currently implemented in Ruby 3.4.0-rc1 -- that would cause issues with my [Marameters](https://alchemists.io/projects/marameters) gem. ⚠️ Please note that the syntax I'm showing you is for the next _major_ release of the gem once Ruby 3.4.0 is released: ``` ruby parameters = proc { it }.parameters signature = Marameters.signature(parameters).to_s # " = nil" Demo = Module.new do module_eval <<~METHOD, __FILE__, __LINE__ + 1 def self.test(#{signature}) = "This is a demo." METHOD end Demo.test # syntax errors found (SyntaxError) # ↑ This is because a method signature of `test( = nil)` is definitely not syntactically valid. ``` I can definitely fix my Marameters gem to account for this use case but would be nice to ensure `Method#parameters` _always_ answers an array than can immediately be used to _dynamically_ build a new method signature that is _syntactically correct_. ---------------------------------------- Bug #20955: Subtle differences with Proc#parameters for anonymous parameters https://bugs.ruby-lang.org/issues/20955#change-111030 * Author: zverok (Victor Shepelev) * Status: Open * ruby -v: ruby 3.4.0dev (2024-12-15T13:36:38Z master 366fd9642f) +PRISM [x86_64-linux] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONTNEED ---------------------------------------- ```ruby p proc { |x| }.parameters #=> [[:opt, :x]] p lambda { |x| }.parameters #=> [[:req, :x]] p proc { _1 }.parameters #=> [[:opt, :_1]] p lambda { _1 }.parameters #=> [[:req, :_1]] p proc { it }.parameters #=> [[:opt, nil]] p lambda { it }.parameters #=> [[:req]] ``` Note the last pair; here are two small confusing problems: 1. For proc, unlike numbered parameters, the parameter name is `nil` (not `it`). This, though, can be justified to distinguish from `proc { |it| }` case 2. But also, `proc` has this `nil` for a parameter name, while `lambda` has not. I am not sure what the “most logical” thing to do here, but I believe that at least `proc { it }` and `lambda { it }` should be made consistent with each other. -- https://bugs.ruby-lang.org/

Issue #20955 has been updated by zverok (Victor Shepelev).
but this behavior would be nice (again, thinking in terms of consistency):
```ruby proc { |_1| }.parameters # _1 is reserved for numbered parameter (SyntaxError) proc { |it| }.parameters # it is a reserved block parameter (SyntaxError) ``` I believe that when `it` was introduced, it was common understanding that it should be as non-invasive as humanly possible, so it should never be deprecated as a local variable name or explicit parameter name. It is a common short word, so amount of codebases that use it, including as an explicit name, is probably significant (as a shortcut for `it`em, or "`i`ndex of `t`ime point" or somesuch). `it` and `_1` are explicitly not, and would not be, consistent by this account and by several others (say, allowing usage in the nested blocks — though the latter seems less justified to me). ---------------------------------------- Bug #20955: Subtle differences with Proc#parameters for anonymous parameters https://bugs.ruby-lang.org/issues/20955#change-111034 * Author: zverok (Victor Shepelev) * Status: Open * ruby -v: ruby 3.4.0dev (2024-12-15T13:36:38Z master 366fd9642f) +PRISM [x86_64-linux] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONTNEED ---------------------------------------- ```ruby p proc { |x| }.parameters #=> [[:opt, :x]] p lambda { |x| }.parameters #=> [[:req, :x]] p proc { _1 }.parameters #=> [[:opt, :_1]] p lambda { _1 }.parameters #=> [[:req, :_1]] p proc { it }.parameters #=> [[:opt, nil]] p lambda { it }.parameters #=> [[:req]] ``` Note the last pair; here are two small confusing problems: 1. For proc, unlike numbered parameters, the parameter name is `nil` (not `it`). This, though, can be justified to distinguish from `proc { |it| }` case 2. But also, `proc` has this `nil` for a parameter name, while `lambda` has not. I am not sure what the “most logical” thing to do here, but I believe that at least `proc { it }` and `lambda { it }` should be made consistent with each other. -- https://bugs.ruby-lang.org/

Issue #20955 has been updated by bkuhlmann (Brooke Kuhlmann). Thanks. When I mentioned "consistency" I was mostly concerned about getting a parameters array from `Proc#parameters` that I could use to construct an equivalent method signature but this won't be a problem with normal method signatures (well, sort of), only procs/lambdas will exhibit this behavior. I guess this is OK but does feel weird especially since you can end up with a required/optional parameter with no name. The only non-proc situation I can think of is when using a required parameter with array destructuring. Example: ``` ruby def demo((one, two)) = puts "One: #{one}, Two: #{two}" method(:demo).parameters # [[:req]] ``` ---------------------------------------- Bug #20955: Subtle differences with Proc#parameters for anonymous parameters https://bugs.ruby-lang.org/issues/20955#change-111040 * Author: zverok (Victor Shepelev) * Status: Open * ruby -v: ruby 3.4.0dev (2024-12-15T13:36:38Z master 366fd9642f) +PRISM [x86_64-linux] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONTNEED ---------------------------------------- ```ruby p proc { |x| }.parameters #=> [[:opt, :x]] p lambda { |x| }.parameters #=> [[:req, :x]] p proc { _1 }.parameters #=> [[:opt, :_1]] p lambda { _1 }.parameters #=> [[:req, :_1]] p proc { it }.parameters #=> [[:opt, nil]] p lambda { it }.parameters #=> [[:req]] ``` Note the last pair; here are two small confusing problems: 1. For proc, unlike numbered parameters, the parameter name is `nil` (not `it`). This, though, can be justified to distinguish from `proc { |it| }` case 2. But also, `proc` has this `nil` for a parameter name, while `lambda` has not. I am not sure what the “most logical” thing to do here, but I believe that at least `proc { it }` and `lambda { it }` should be made consistent with each other. -- https://bugs.ruby-lang.org/

Issue #20955 has been updated by k0kubun (Takashi Kokubun). Agreed that `it` should work like `_1` here. You couldn't distinguish `proc {it}.parameters` with `proc {|it|}.parameters`, but these procs work in the same way anyway, so it shouldn't matter. Note that nobu's PR https://github.com/ruby/ruby/pull/12398 for https://bugs.ruby-lang.org/issues/20965 fixes this too. ---------------------------------------- Bug #20955: Subtle differences with Proc#parameters for anonymous parameters https://bugs.ruby-lang.org/issues/20955#change-111088 * Author: zverok (Victor Shepelev) * Status: Open * ruby -v: ruby 3.4.0dev (2024-12-15T13:36:38Z master 366fd9642f) +PRISM [x86_64-linux] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONTNEED ---------------------------------------- ```ruby p proc { |x| }.parameters #=> [[:opt, :x]] p lambda { |x| }.parameters #=> [[:req, :x]] p proc { _1 }.parameters #=> [[:opt, :_1]] p lambda { _1 }.parameters #=> [[:req, :_1]] p proc { it }.parameters #=> [[:opt, nil]] p lambda { it }.parameters #=> [[:req]] ``` Note the last pair; here are two small confusing problems: 1. For proc, unlike numbered parameters, the parameter name is `nil` (not `it`). This, though, can be justified to distinguish from `proc { |it| }` case 2. But also, `proc` has this `nil` for a parameter name, while `lambda` has not. I am not sure what the “most logical” thing to do here, but I believe that at least `proc { it }` and `lambda { it }` should be made consistent with each other. -- https://bugs.ruby-lang.org/

Issue #20955 has been updated by k0kubun (Takashi Kokubun). Status changed from Closed to Open Since fixing this raised issues like https://bugs.ruby-lang.org/issues/20970 and it's too close to the release to design the behavior properly, we reverted https://github.com/ruby/ruby/pull/12398 for Ruby 3.4. ---------------------------------------- Bug #20955: Subtle differences with Proc#parameters for anonymous parameters https://bugs.ruby-lang.org/issues/20955#change-111148 * Author: zverok (Victor Shepelev) * Status: Open * ruby -v: ruby 3.4.0dev (2024-12-15T13:36:38Z master 366fd9642f) +PRISM [x86_64-linux] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONTNEED ---------------------------------------- ```ruby p proc { |x| }.parameters #=> [[:opt, :x]] p lambda { |x| }.parameters #=> [[:req, :x]] p proc { _1 }.parameters #=> [[:opt, :_1]] p lambda { _1 }.parameters #=> [[:req, :_1]] p proc { it }.parameters #=> [[:opt, nil]] p lambda { it }.parameters #=> [[:req]] ``` Note the last pair; here are two small confusing problems: 1. For proc, unlike numbered parameters, the parameter name is `nil` (not `it`). This, though, can be justified to distinguish from `proc { |it| }` case 2. But also, `proc` has this `nil` for a parameter name, while `lambda` has not. I am not sure what the “most logical” thing to do here, but I believe that at least `proc { it }` and `lambda { it }` should be made consistent with each other. -- https://bugs.ruby-lang.org/

Issue #20955 has been updated by alanwu (Alan Wu). Status changed from Open to Closed AFAICT #20974 fully addressed the issue in the OP, and `it` behaves the same as anonymous destructuring parameters. ```shell $ ./miniruby -ve 'p proc { it }.parameters #=> [[:opt, nil]] p lambda { it }.parameters #=> [[:req]]' ruby 3.5.0dev (2025-01-14T16:46:11Z master b076e9b7ac) +PRISM [arm64-darwin24] [[:opt]] [[:req]] ``` ---------------------------------------- Bug #20955: Subtle differences with Proc#parameters for anonymous parameters https://bugs.ruby-lang.org/issues/20955#change-111491 * Author: zverok (Victor Shepelev) * Status: Closed * ruby -v: ruby 3.4.0dev (2024-12-15T13:36:38Z master 366fd9642f) +PRISM [x86_64-linux] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONTNEED ---------------------------------------- ```ruby p proc { |x| }.parameters #=> [[:opt, :x]] p lambda { |x| }.parameters #=> [[:req, :x]] p proc { _1 }.parameters #=> [[:opt, :_1]] p lambda { _1 }.parameters #=> [[:req, :_1]] p proc { it }.parameters #=> [[:opt, nil]] p lambda { it }.parameters #=> [[:req]] ``` Note the last pair; here are two small confusing problems: 1. For proc, unlike numbered parameters, the parameter name is `nil` (not `it`). This, though, can be justified to distinguish from `proc { |it| }` case 2. But also, `proc` has this `nil` for a parameter name, while `lambda` has not. I am not sure what the “most logical” thing to do here, but I believe that at least `proc { it }` and `lambda { it }` should be made consistent with each other. -- https://bugs.ruby-lang.org/
participants (4)
-
alanwu (Alan Wu)
-
bkuhlmann (Brooke Kuhlmann)
-
k0kubun (Takashi Kokubun)
-
zverok (Victor Shepelev)