[go: up one dir, main page]
More Web Proxy on the site http://driver.im/

Project

General

Profile

Actions

Bug #20965

open

`it` vs `binding.local_variables`

Added by zverok (Victor Shepelev) 17 days ago. Updated 13 days ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 3.4.0dev (2024-12-15T13:36:38Z master 366fd9642f) +PRISM [x86_64-linux]
[ruby-core:120303]

Description

it is not available in the list of binding.local_varaibles, unlike numbered parameters:

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.


Related issues 1 (0 open1 closed)

Related to Ruby master - Feature #18980: `it` as a default block parameterClosedk0kubun (Takashi Kokubun)Actions
Actions #1

Updated by zverok (Victor Shepelev) 17 days ago

  • ruby -v set to ruby 3.4.0dev (2024-12-15T13:36:38Z master 366fd9642f) +PRISM [x86_64-linux]

Updated by shan (Shannon Skipper) 17 days ago

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.

proc { _9; local_variables }.call
# => [:_1, :_2, :_3, :_4, :_5, :_6, :_7, :_8, :_9]

proc { it; local_variables }.call
# => []
Actions #4

Updated by k0kubun (Takashi Kokubun) 17 days ago

Actions #5

Updated by nobu (Nobuyoshi Nakada) 17 days ago

  • Status changed from Open to Closed

Applied in changeset git|46fec0f62a1803d44edb8b06e39ac0f358e56670.


[Bug #20965] Define it like an ordinary argument (#12398)

Also fixes [Bug #20955]

Updated by tompng (tomoya ishida) 17 days ago

I have a concern of making it parameter an lvar.

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.

Updated by mame (Yusuke Endoh) 13 days ago

  • Status changed from Closed to Open

Let's revert this change.

Below is our local discussion of this issue with @nobu (Nobuyoshi Nakada) and @ko1 (Koichi Sasada).

First, consider the following example.

"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 (Koichi Sasada) said). 3 is clearly counterintuitive.

Then, consider the following example.

"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.

Actions #8

Updated by k0kubun (Takashi Kokubun) 13 days ago

  • Status changed from Open to Closed

Applied in changeset git|667a0f9f928be843a0810f2c61b633be1f8cd46a.


Revert "[Bug #20965] Define it like an ordinary argument" (#12418)

Revert "[Bug #20965] Define it like an ordinary argument (#12398)"

Reverts ruby/ruby#12398 as per https://bugs.ruby-lang.org/issues/20970#note-6 and https://bugs.ruby-lang.org/issues/20965#note-7.
We need more time to design the intended behavior, and it's too late for Ruby 3.4.

Updated by k0kubun (Takashi Kokubun) 13 days ago

  • 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.

Updated by zverok (Victor Shepelev) 13 days ago

Interestingly, numbered block parameters do this:

"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: its behavior, after the change is reverted, actually seems more internally consistent at least between local_variables and eval, so maybe numbered parameters should follow?)

Updated by mame (Yusuke Endoh) 13 days ago

I see. I think this is simply buggy.

"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.

Actions

Also available in: Atom PDF

Like1
Like0Like0Like3Like0Like0Like0Like0Like0Like0Like0Like0