Bug #20043
open`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) 5 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) 5 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) 4 months ago
It seems a bug from Ruby 2.2.
Updated by Dan0042 (Daniel DeLorme) 4 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) 4 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) 4 months ago
I submitted a pull request to fix this: https://github.com/ruby/ruby/pull/9500
Updated by ko1 (Koichi Sasada) 2 months ago
In future, should we deprecate defined? usecase which return expression
?