Bug #20043
closed`defined?` checks for method existence but only sometimes
Description
When an expression is passed to defined?
, it will sometimes check if a method in a sub-expression is defined and sometimes it won't.
For example:
$ ./miniruby -e'p defined?(a)'
nil
$ ./miniruby -e'p defined?([a])'
nil
In the above case, Ruby will check whether or not the method a
is defined, and it returns nil
. However, if you use a splat, it will not check:
$ ./miniruby -e'p defined?([*a])'
"expression"
The same thing seems to happen with method parameters:
$ ./miniruby -e'p defined?(itself)'
"method"
$ ./miniruby -e'p defined?(itself(a))'
nil
$ ./miniruby -e'p defined?(itself(*a))'
"method"
Oddly, defined?
will check contents of arrays, but won't check contents of hashes:
$ ./miniruby -e'p defined?([[[[a]]]])'
nil
$ ./miniruby -e'p defined?({ a => a })'
"expression"
I think all of the cases that refer to a
should check whether or not a
is defined regardless of splats or hashes.
Files
Updated by Eregon (Benoit Daloze) 11 months ago
I wonder if defined?
should only be defined for constant paths and method call without arguments, e.g. defined?(RubyVM.keep_script_lines)
.
Is there any use case for defined?
besides those?
IOW, I think the simpler defined?
is the better (less complexity in Ruby implementations, I think little value in practice).
That could mean don't recurse into nested nodes or so, except for constant paths.
Updated by byroot (Jean Boussier) 11 months ago
Is there any use case for defined? besides those?
Instance variables for sure: defined?(@ivar)
.
Also checking for super: defined?(super)
.
Some people use it for a sequence of calls: defined?(foo.bar.baz)
.
Updated by ko1 (Koichi Sasada) 11 months ago
It seems a bug from Ruby 2.2.
Updated by Dan0042 (Daniel DeLorme) 11 months ago
I didn't know about this way of using defined?
and it's interesting to me that we can check if multiple things are defined at once. Although the 3rd case below is another example that seems odd. But both that and defined?([*a])
return "expression" since ruby 1.9, not 2.2
x = 1
defined?(x) and defined?(y) and defined?(z) #=> nil
defined?([x, y, z]) #=> nil (shorter!)
defined?(x && y && z) #=> "expression" (???)
defined?(x & y & z) #=> nil
Updated by tenderlovemaking (Aaron Patterson) 11 months ago
- File general - ruby-lang - 4 new items - Slack 2023-12-19 16-10-39.png general - ruby-lang - 4 new items - Slack 2023-12-19 16-10-39.png added
ko1 (Koichi Sasada) wrote in #note-3:
It seems a bug from Ruby 2.2.
I think itself
was added in Ruby 2.2. Seems this bug is perhaps from Ruby 1.9?
Dan0042 (Daniel DeLorme) wrote in #note-4:
I didn't know about this way of using
defined?
and it's interesting to me that we can check if multiple things are defined at once.
Yes, I thought so too. I can understand the utility of defined?([x, y, z])
, but I can't tell if that was intended? Especially considering the x && y && z
case.
Also defined?([x, y, z])
will return "expression" if x, y, and z are defined. But [x, y, z]
seems like an expression regardless of whether or not those are defined (the expression just might raise though).
Updated by jeremyevans0 (Jeremy Evans) 10 months ago
I submitted a pull request to fix this: https://github.com/ruby/ruby/pull/9500
Updated by ko1 (Koichi Sasada) 9 months ago
In future, should we deprecate defined? usecase which return expression
?
Updated by mame (Yusuke Endoh) 5 months ago
Discussed at the dev meeting. @matz (Yukihiro Matsumoto) said defined?([*a])
, defined?(itself(*a))
, and defined?({ a => a })
should all return nil.
Matz was not positive about restricting the expression of defined?
. @ko1 (Koichi Sasada) said he will investigate the use case in public gem code base.
Updated by ko1 (Koichi Sasada) 5 months ago
Here is a survey which node (in Prism) are used in defined?(expr)
(the node of expr
)
https://gist.github.com/ko1/b31517a5037d55bbe50e7f12d79b9fc1
I understand the usage of :constant_read_node, :constant_path_node, :instance_variable_read_node, :call_node, :global_variable_read_node, :class_variable_read_node, :forwarding_super_node, :numbered_reference_read_node, :yield_node, :super_node, but not sure other nodes.
https://gist.github.com/ko1/fcf98c0fec3aecfdae7f1a4d91ee5626
is a survey of other nodes.
There are misusages like defined? C ? x : y
(expected defined?(C) ? x : y
but defined?(C ? x : y)
which always returns "expression"
.
Updated by jeremyevans (Jeremy Evans) 4 months ago
- Status changed from Open to Closed
Applied in changeset git|ae0c7faa79029ebe615487d23c8ee1ca44ce4a36.
Handle hash and splat nodes in defined?
This supports the nodes in both in the parse.y and prism compilers.
Fixes [Bug #20043]
Co-authored-by: Kevin Newton kddnewton@gmail.com