Bug #20478
closedCircular parameter syntax error rules
Description
I would like to revisit https://bugs.ruby-lang.org/issues/16343.
These cases are syntax errors:
def foo(bar = -> { bar }) end # no lambda parameters
def foo(bar = ->() { bar }) end # no lambda parameters
def foo(bar = baz { bar }) end # no block parameters
def foo(bar = baz { _1 + bar }) end # parameters, but no pipes
def foo(bar = baz { it + bar }) end # parameters, but no pipes
These cases are not syntax errors:
def foo(bar = ->(baz) { bar }) end # lambda parameters
def foo(bar = baz { || bar }) end # no block parameters but empty pipes
def foo(bar = baz { |qux| bar }) end # block parameters
I don't think these rules are very intuitive, and they feel somewhat arbitrary. I would like to suggest we change them to be either:
- Syntax error is raised if the parameter is ever read in its default value at any scope depth
- Syntax error is raised if the parameter is ever read in its default value at depth 0
Either one is fine by me, but gating the syntax error based on the presence of pipes is really confusing.
Updated by nobu (Nobuyoshi Nakada) 10 months ago
Given that these Proc
s are only created if the argument bar
is not assigned, should they all be syntax errors?
Updated by kddnewton (Kevin Newton) 10 months ago
Yes, I very much think they should all be syntax errors.
Updated by nobu (Nobuyoshi Nakada) 10 months ago
Even this should be a syntax error?
def foo(bar = ->(baz = bar) {}) end
That means it needs to manage the list of yet-unusable variables, not only tracking single variable.
Updated by kddnewton (Kevin Newton) 10 months ago
I figured that was already happening for the "unused" warning.
Updated by byroot (Jean Boussier) 10 months ago
- Related to Bug #16343: Inconsistent behavior of 'circular argument reference' error added
Updated by kddnewton (Kevin Newton) 9 months ago
@nobu (Nobuyoshi Nakada) another option would be to delete those tests and leave it up to the parser instead of forcing parse.y to implement it. Specifically I'm talking about:
o = Object.new
assert_warn("") do
o.instance_eval("def foo(var: bar {| | var}) var end")
end
o = Object.new
assert_warn("") do
o.instance_eval("def foo(var: bar {|| var}) var end")
end
and
o = Object.new
assert_warn("") do
o.instance_eval("def foo(var = bar {| | var}) var end")
end
o = Object.new
assert_warn("") do
o.instance_eval("def foo(var = bar {|| var}) var end")
end
If it's too complicated to implement in parse.y, then removing these tests would be a good compromise. These tests themselves are the issue blocking me.
Updated by kddnewton (Kevin Newton) 9 months ago
If we go with only syntax errors at depth 0, then this:
def foo(bar = baz { bar }) end
should not be a syntax error either. I think that makes sense, because the baz
method could use instance_exec
/instance_eval
so we don't know if bar
is going to be the same variable here or not.
Updated by kddnewton (Kevin Newton) 9 months ago
Also:
def foo(bar = -> { bar }) end
def foo(bar = ->( ) { bar }) end
def foo(bar = ->(_) { bar }) end
Two of these are a syntax error, but I think either all of them should be or none of them should be.
Updated by mame (Yusuke Endoh) 9 months ago
Discussed at the dev meeting. @matz (Yukihiro Matsumoto) said all cases should be accepted with no syntax error. So def foo(bar = bar) = bar; foo
will return nil
with no warning and error.
Updated by Earlopain (Earlopain _) 2 months ago
This used to emit a warning since all the way back from Ruby 2.2, before it was invalid syntax. Should the warning be reintroduced?