Bug #16293
Updated by osyo (manga osyo) almost 5 years ago
## Overview I want to make a final check on the behavior of Numbered parameter( No warning or Warning or Error). Error. * No warning -> No error in the future There is a difference * Warning -> Deprecated syntax * Error -> Error in [DevelopersMeeting20190829Japan logs](https://docs.google.com/document/d/1XypDO1crRV9uNg1_ajxkljVdN8Vdyl5hnz462bDQw34/edit) and behavior. Ruby 2.7 ## Ruby version ```ruby p RUBY_VERSION # => "2.7.0" p RUBY_DESCRIPTION # => "ruby 2.7.0dev (2019-11-02T06:32:49Z trunk 772b0613c5) [x86_64-linux]" p RUBY_RELEASE_DATE # => "2019-11-02" p RUBY_REVISION # => "772b0613c583773cd2eda23bce8275926a351e79" ``` ## [DevelopersMeeting20190829Japan logs](https://docs.google.com/document/d/1XypDO1crRV9uNg1_ajxkljVdN8Vdyl5hnz462bDQw34/edit) [Log in DevelopersMeeting20190829Japan](https://docs.google.com/document/d/1XypDO1crRV9uNg1_ajxkljVdN8Vdyl5hnz462bDQw34/edit) * local variables (parameters and assigned variable) → force warning (Don’t use) on Ruby 2.7 and syntax error on Ruby 3. * method invocation * vcall: `x = _0 # expect _0()` outside block. → force warning on Ruby 2.7 and syntax error on Ruby 3. * vcall: `1.times{ _0 }` → block parameter (incompatibility) * vcall: `1.times{|i| _0 }` → force warning on Ruby 2.7 and syntax error on Ruby 3. * method invocation (`x = _0(), x = foo._0`) → no warning * method name (`def _0(); end`) → no warning ## Proposal Current behavior ```ruby # No warning # Defined parameter name `_1` def _1; hgoe(_1) end ``` ```ruby def _1 :method end # expected: warning: `_1' is used as No warning # Call to method `_1` x = _1 p x # => :method # Error: numbered parameter outside block (SyntaxError) p eval("_1") ``` ```ruby def _1 :method end # actual: Error: ordinary parameter is defined p proc { |i| _1 }.call 42 ``` ```ruby proc { # Warning _1 = 42 } proc { _1 # No warning # Defined local variable _1 = 42 } ``` ```ruby def _1 :method end # reason: Because No warning p _1 # Error: numbered parameter outside block (SyntaxError) p eval("_1") ``` ## Proposal * When deprecated in the future, it is necessary to issue a Warning * Considering compatibility, make it Warning instead of Error ```ruby def _1 :method end # Warning # "`x = _0 # expect _0()` outside block. → force warning on Ruby 2.7 and syntax error on Ruby 3" is written in the log logs x = _1 # expected: warning: `_1' is used as numbered parameter # and call to _1() p x # actual: Error: numbered parameter outside block (SyntaxError) => :method # reason: Because hoge() method is called with `eval("hoge")` Warning p eval("_1") ``` ```ruby def _1; _1 :method end # expected: warning: `_1' is used as numbered parameter Warning # and call to _1() # actual: Error: ordinary parameter is defined # reason: Because "`1.times{|i| _0 }` → force warning on Ruby 2.7 and syntax error on Ruby 3." is written in the log logs p proc { |i| _1 }.call 42 ``` ```ruby proc { # expected: warning: Warning _1 = 42 } proc { _1 # Warning _1 = 42 } ``` ```ruby # Warning # Since local variables are also warnings, formal parameters are also warnings def hgoe(_1) end # NOTE # `eval("_1")` refers to a dummy argument def hoge(_1) p proc { _1 eval("_1") }.call 42 end hoge :argument # => :argument ``` ## Other behavior * Is there any other syntax to change `No warning` `Warning` `Error` ? ### Example 1. Defined local variable name `_1` ```ruby # Example 1-1 # Warning : defined local variable _1 = 42 ``` ```ruby # Example 1-2 # No warning : defined method name def _1 42 end ``` ```ruby # Example 1-3 # No warning : defined parameter name def hgoe(_1) end ``` ```ruby # Example 1-4 # In block proc { # Warning: `_1' is used as numbered Numbered parameter _1 = 42 } # actual: Example 1-5 # In block and used Numbered parameter proc { _1 # No warning _1 = 42 # reason: Because define } ``` ### Example 2. Refer to local variable `_1` in block ```ruby _1 is = :local_variable # Example 2-1 # No warning x = _1 p x # => :local_variable # Example 2-2 # No warning p proc { |i| _1 }.call 3 # => :local_variable # Example 2-3 # No warning p proc { _1 }.call 3 # => :local_variable # Example 2-4 p proc { _1 proc { # No warning _1 }.call }.call 42 # => :local_variable ``` ### Example 3. Refer to method `_1` in block ```ruby def hgoe(_1) _1(a = nil) :"method#{a}" end # Example 3-1 # No warning x = _1 p x # => :method # Example 3-2 # No warning x = _1 42 p x # => :method42 # Example 3-3 # No warning x = _1() p x # => :method # Example 3-4 # Error p proc { |i| _1 }.call 42 # Example 3-5 # No warning p proc { |i| _1() }.call 42 # => :method # Example 3-6 # No warning p proc { |i| _1 i }.call 42 # => :method42 # Example 3-7 # No warning p proc { |i| self._1 }.call 42 # => :method # Example 3-8 # No warning p proc { _1 }.call 42 # => 42 # Example 3-9 # No warning p proc { _1 _2 }.call 42, 3 # => method3 # Example 3-10 # No warning p proc { _1() }.call 42 # => :method # Example 3-11 # No warning p proc { self._1 }.call 42 # => :method ``` ### Example 4. Defined local variable `_1` and method `_1` ```ruby def _1(a = nil) :"method#{a}" end _1 = :local_variable # Example 4-1 # No warning p proc { |i| _1 }.call 3 # => :local_variable # Example 4-2 # No warning p proc { |i| _1() }.call 3 # => :method # Example 4-3 # No warning p proc { |i| _1 42 }.call 3 # => :method42 # Example 4-4 # No warning p proc { _1 }.call 3 # => :local_variable # Example 4-5 # No warning p proc { _1() }.call 3 # => :method # Example 4-6 # No warning p proc { _1 42 }.call 3 # => :method42 ``` ### Example 5. Used `eval("_1")` * `eval ("_1")` refers to local variables in preference * The same goes for `binding.local_variable_get(:_1)` * If local variable `_1` becomes Error, solve it? * `eval("@1")` is Syntax Error ```ruby # Warning Example 5-1 # Error: numbered parameter outside block (SyntaxError) p proc { eval("_1") }.call 42 ``` ```ruby # Example 5-2 # No warning p proc { _1; eval("_1") }.call 42 # => 42 ``` ```ruby _1 = :local_variable # Example 5-3 # No warning p eval("_1") # => :local_variable # Example 5-4 # No warning p proc { eval("_1") }.call 42 } # => :local_variable # Example 5-5 # No warning p proc { _1; eval("_1") }.call 42 # => :local_variable ``` ```ruby # Example 5-6 p proc { _1 # expected: warning: `_1' Error: numbered parameter is already used as numbered parameter in # actual: outer block here proc { _1 }.call 3 }.call 42 ``` ```ruby # Example 5-7 p proc { _1 proc { # No warning eval("_1") }.call 3 }.call 42 # reason: Because define local variable => 42 ``` ```ruby # Example 5-8 _1 is = :local_variable p proc { _1 proc { # No warning eval("_1") }.call 3 }.call 42 # => :local_variable ``` ```ruby def _1 :method end # Example 5-9 # No warning p _1 # => :method # Example 5-10 # Error: numbered parameter outside block (SyntaxError) p eval("_1") # Example 5-11 # No warning p eval("_1()") # => :method # Example 5-12 # Error: numbered parameter outside block (SyntaxError) p proc { eval("_1") }.call 42 # Example 5-13 # No warning p proc { _1; eval("_1") }.call 42 # => 42 ``` ### Example 6. Used default arguments ```ruby # Example 6-1 # OK p proc { |_1| -> (a = _1) { a }.call }.call 42 } # => 42 ``` ## :MEMO: Other behavior ```ruby # Example 6-2 # OK _1 = :local_variable p proc { -> (a = _1) { a }.call }.call 42 # => :local_variable ``` * Other current behavior : https://gist.github.com/osyo-manga/f332ba1f31dbc3a437acd4d86d7986dc ```ruby * Is there any other syntax # OK def _1 :method end p proc { _1 eval("_1") }.call 42 # => 42 ``` ```ruby # Example 6-3 # NG p proc { # Error: ordinary parameter is defined -> (a = _1) { a }.call }.call 42 ``` ```ruby # Example 6-4 # OK p proc { |_1| -> (a = _1) { a }.call }.call 42 # => 42 ``` ```ruby # Example 6-5 # OK _1 = :local_variable p proc { -> (a = _1) { a }.call }.call 42 # => :local_variable ``` ```ruby # Example 6-6 # NG p proc { # Error: ordinary parameter is defined -> (a = _1) { a }.call }.call 42 ``` ### Example 7. Refrer to change `No warning` `Warning` `Error` ? `_1` in binding.irb ```ruby * Considering compatibility, make it Warning instead of Error ? # Example 7-1 proc { _1 # Referencing _1 returns 42 binding.irb }.call 42 ``` ```ruby # Example 7-2 _1 = :local_variable proc { _1 # Referencing _1 returns :local_variable binding.irb }.call 42 ``` Are there other edge cases for Numbered parameter? Thank you :)