[ruby-core:120303] [Ruby master Bug#20965] `it` vs `binding.local_variables`

Issue #20965 has been reported by zverok (Victor Shepelev). ---------------------------------------- Bug #20965: `it` vs `binding.local_variables` https://bugs.ruby-lang.org/issues/20965 * Author: zverok (Victor Shepelev) * Status: Open * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONTNEED ---------------------------------------- `it` is not available in the list of `binding.local_varaibles`, **unlike** numbered parameters: ```ruby p(proc { binding.local_variables }.call) # [] p(proc { |x| binding.local_variables }.call) # [:x] p(proc { _1; binding.local_variables }.call) # [:_1] p(proc { vars = binding.local_variables; _1; vars }.call) # [:_1, :vars] p(proc { it; binding.local_variables }.call) # [] ``` I wonder if it is deliberate or accidental. -- https://bugs.ruby-lang.org/

Issue #20965 has been updated by shan (Shannon Skipper). It does seem like that last one should be `[:it]` for consistency if it wasn't intentional. +1 An aside, but it's also interesting that using `_2` causes `_1` to also be defined under Binding#local_variables. ``` ruby proc { _9; local_variables }.call # => [:_1, :_2, :_3, :_4, :_5, :_6, :_7, :_8, :_9] proc { it; local_variables }.call # => [] ``` ---------------------------------------- Bug #20965: `it` vs `binding.local_variables` https://bugs.ruby-lang.org/issues/20965#change-111074 * 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 ---------------------------------------- `it` is not available in the list of `binding.local_varaibles`, **unlike** numbered parameters: ```ruby p(proc { binding.local_variables }.call) # [] p(proc { |x| binding.local_variables }.call) # [:x] p(proc { _1; binding.local_variables }.call) # [:_1] p(proc { vars = binding.local_variables; _1; vars }.call) # [:_1, :vars] p(proc { it; binding.local_variables }.call) # [] ``` I wonder if it is deliberate or accidental. -- https://bugs.ruby-lang.org/

Issue #20965 has been updated by nobu (Nobuyoshi Nakada). https://github.com/ruby/ruby/pull/12398 ---------------------------------------- Bug #20965: `it` vs `binding.local_variables` https://bugs.ruby-lang.org/issues/20965#change-111081 * 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 ---------------------------------------- `it` is not available in the list of `binding.local_varaibles`, **unlike** numbered parameters: ```ruby p(proc { binding.local_variables }.call) # [] p(proc { |x| binding.local_variables }.call) # [:x] p(proc { _1; binding.local_variables }.call) # [:_1] p(proc { vars = binding.local_variables; _1; vars }.call) # [:_1, :vars] p(proc { it; binding.local_variables }.call) # [] ``` I wonder if it is deliberate or accidental. -- https://bugs.ruby-lang.org/

Issue #20965 has been updated by tompng (tomoya ishida). I have a concern of making `it` parameter an lvar. ~~~ruby 1| 42.tap do 2| p binding.local_variable_get('it') 3| it /1/i 4| p it 5| end ~~~ When parser reads `p it` at line 4, `it` turns out to be a local variable, I think from the beginning of the block(from line 2). But on line 3, `it /1/i` is already parsed as if lvar `it` does not exist. It is impossible to re-parse the block again, so the original implementation(it parameter is not an lvar) makes sense to me. ---------------------------------------- Bug #20965: `it` vs `binding.local_variables` https://bugs.ruby-lang.org/issues/20965#change-111096 * 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 ---------------------------------------- `it` is not available in the list of `binding.local_varaibles`, **unlike** numbered parameters: ```ruby p(proc { binding.local_variables }.call) # [] p(proc { |x| binding.local_variables }.call) # [:x] p(proc { _1; binding.local_variables }.call) # [:_1] p(proc { vars = binding.local_variables; _1; vars }.call) # [:_1, :vars] p(proc { it; binding.local_variables }.call) # [] ``` I wonder if it is deliberate or accidental. -- https://bugs.ruby-lang.org/

Issue #20965 has been updated by mame (Yusuke Endoh). Status changed from Closed to Open Let's revert this change. Below is our local discussion of this issue with @nobu and @ko1. First, consider the following example. ```ruby "foo".tap do it "bar".tap do p eval("it") # what should happen? end end ``` There are three possible options. 1. Raises an exeption 2. Returns `"bar"` 3. Returns `"foo"` 1 is the only realistic choice. 2 would require keeping all arguments conservatively even when `it` does not appear lexically, which we want to avoid for a performance reason (including the possibility of future optimizations, as @ko1 said). 3 is clearly counterintuitive. Then, consider the following example. ```ruby "foo".tap do it "bar".tap do p binding.local_variables #=> []? [:it]? eval("it") end end ``` If `local_variables` contains `:it`, `eval("it")` is expected to return some value. However, it is impossible for the reason above. Therefore, `local_variables` should return `[]`. The difference between `_1` and `it` is that `_1` is prohibited to be referenced outside of a block, while `it` is not. Note that if `it` is defined as an ordinary local variable by an assignment, `local_variables` should contain `:it`. ---------------------------------------- Bug #20965: `it` vs `binding.local_variables` https://bugs.ruby-lang.org/issues/20965#change-111145 * 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 ---------------------------------------- `it` is not available in the list of `binding.local_varaibles`, **unlike** numbered parameters: ```ruby p(proc { binding.local_variables }.call) # [] p(proc { |x| binding.local_variables }.call) # [:x] p(proc { _1; binding.local_variables }.call) # [:_1] p(proc { vars = binding.local_variables; _1; vars }.call) # [:_1, :vars] p(proc { it; binding.local_variables }.call) # [] ``` I wonder if it is deliberate or accidental. -- https://bugs.ruby-lang.org/

Issue #20965 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 (particularly relevant to this #20965) 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 #20965: `it` vs `binding.local_variables` https://bugs.ruby-lang.org/issues/20965#change-111149 * 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 ---------------------------------------- `it` is not available in the list of `binding.local_varaibles`, **unlike** numbered parameters: ```ruby p(proc { binding.local_variables }.call) # [] p(proc { |x| binding.local_variables }.call) # [:x] p(proc { _1; binding.local_variables }.call) # [:_1] p(proc { vars = binding.local_variables; _1; vars }.call) # [:_1, :vars] p(proc { it; binding.local_variables }.call) # [] ``` I wonder if it is deliberate or accidental. -- https://bugs.ruby-lang.org/

Issue #20965 has been updated by zverok (Victor Shepelev). Interestingly, numbered block parameters do this: ```ruby "foo".tap do _1 "bar".tap do p binding.local_variables #=> [_1] eval("_1") # undefined local variable or method '_1' for main:Object (NameError) end end ``` I am not saying this is good behavior, though. The things I am concerned about (after the release, of course): 1. Whatever the behavior is, it is deliberate and documented; 2. Whatever the behavior is, it is internally consistent (e.g., in #20955 the thing that surprised me was an inconsistency between proc and lambda); 3. Whatever the behavior is, I’d expect it to be as consistent as possible between `it` and numbered anonymous parameters. (About the latter one: `it`s behavior, after the change is reverted, actually seems more internally consistent at least between `local_variables` and `eval`, so maybe numbered parameters should follow?) ---------------------------------------- Bug #20965: `it` vs `binding.local_variables` https://bugs.ruby-lang.org/issues/20965#change-111151 * 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 ---------------------------------------- `it` is not available in the list of `binding.local_varaibles`, **unlike** numbered parameters: ```ruby p(proc { binding.local_variables }.call) # [] p(proc { |x| binding.local_variables }.call) # [:x] p(proc { _1; binding.local_variables }.call) # [:_1] p(proc { vars = binding.local_variables; _1; vars }.call) # [:_1, :vars] p(proc { it; binding.local_variables }.call) # [] ``` I wonder if it is deliberate or accidental. -- https://bugs.ruby-lang.org/

Issue #20965 has been updated by mame (Yusuke Endoh). I see. I think this is simply buggy. ```ruby "foo".tap do _1 "bar".tap do p binding.local_variable_get(:_1) #=> "foo" end end ``` IMO, meta-programming APIs for numbered parameters and `it` should be separated from `binding#local_variable*` because they are not a local variable. It would be good to consider them towards 3.5. ---------------------------------------- Bug #20965: `it` vs `binding.local_variables` https://bugs.ruby-lang.org/issues/20965#change-111152 * 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 ---------------------------------------- `it` is not available in the list of `binding.local_varaibles`, **unlike** numbered parameters: ```ruby p(proc { binding.local_variables }.call) # [] p(proc { |x| binding.local_variables }.call) # [:x] p(proc { _1; binding.local_variables }.call) # [:_1] p(proc { vars = binding.local_variables; _1; vars }.call) # [:_1, :vars] p(proc { it; binding.local_variables }.call) # [] ``` I wonder if it is deliberate or accidental. -- https://bugs.ruby-lang.org/

Issue #20965 has been updated by mame (Yusuke Endoh). We discussed this at the dev meeting. The above behavior of `p binding.local_variable_get(:_1)` is considered a bug. Neither numbered parameters nor “it” should be considered as local variables. They should not be included in `binding#local_variables` or taken by `binding#local_variable_get`. I will do more research by implementing a patch and performing an experiment, and create a separate ticket. ---------------------------------------- Bug #20965: `it` vs `binding.local_variables` https://bugs.ruby-lang.org/issues/20965#change-111400 * 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 ---------------------------------------- `it` is not available in the list of `binding.local_varaibles`, **unlike** numbered parameters: ```ruby p(proc { binding.local_variables }.call) # [] p(proc { |x| binding.local_variables }.call) # [:x] p(proc { _1; binding.local_variables }.call) # [:_1] p(proc { vars = binding.local_variables; _1; vars }.call) # [:_1, :vars] p(proc { it; binding.local_variables }.call) # [] ``` I wonder if it is deliberate or accidental. -- https://bugs.ruby-lang.org/

Issue #20965 has been updated by mame (Yusuke Endoh). I have created a new issue as #21049. ---------------------------------------- Bug #20965: `it` vs `binding.local_variables` https://bugs.ruby-lang.org/issues/20965#change-111577 * 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 ---------------------------------------- `it` is not available in the list of `binding.local_varaibles`, **unlike** numbered parameters: ```ruby p(proc { binding.local_variables }.call) # [] p(proc { |x| binding.local_variables }.call) # [:x] p(proc { _1; binding.local_variables }.call) # [:_1] p(proc { vars = binding.local_variables; _1; vars }.call) # [:_1, :vars] p(proc { it; binding.local_variables }.call) # [] ``` I wonder if it is deliberate or accidental. -- https://bugs.ruby-lang.org/
participants (6)
-
k0kubun (Takashi Kokubun)
-
mame (Yusuke Endoh)
-
nobu (Nobuyoshi Nakada)
-
shan (Shannon Skipper)
-
tompng (tomoya ishida)
-
zverok (Victor Shepelev)