[ruby-core:115595] [Ruby master Bug#20043] `defined?` checks for method existence but only sometimes

Issue #20043 has been reported by tenderlovemaking (Aaron Patterson). ---------------------------------------- Bug #20043: `defined?` checks for method existence but only sometimes https://bugs.ruby-lang.org/issues/20043 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-12-05T21:25:34Z master 56eccb350b) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- 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. -- https://bugs.ruby-lang.org/

Issue #20043 has been updated by Eregon (Benoit Daloze). 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. ---------------------------------------- Bug #20043: `defined?` checks for method existence but only sometimes https://bugs.ruby-lang.org/issues/20043#change-105536 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-12-05T21:25:34Z master 56eccb350b) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- 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. -- https://bugs.ruby-lang.org/

Issue #20043 has been updated by byroot (Jean Boussier).
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)`. ---------------------------------------- Bug #20043: `defined?` checks for method existence but only sometimes https://bugs.ruby-lang.org/issues/20043#change-105540 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-12-05T21:25:34Z master 56eccb350b) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- 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. -- https://bugs.ruby-lang.org/

Issue #20043 has been updated by ko1 (Koichi Sasada). File clipboard-202312191405-owvpy.png added It seems a bug from Ruby 2.2.  ---------------------------------------- Bug #20043: `defined?` checks for method existence but only sometimes https://bugs.ruby-lang.org/issues/20043#change-105725 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-12-05T21:25:34Z master 56eccb350b) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- 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-------------------------------- clipboard-202312191405-owvpy.png (27.3 KB) -- https://bugs.ruby-lang.org/

Issue #20043 has been updated by Dan0042 (Daniel DeLorme). 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 ```ruby 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 ``` ---------------------------------------- Bug #20043: `defined?` checks for method existence but only sometimes https://bugs.ruby-lang.org/issues/20043#change-105738 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-12-05T21:25:34Z master 56eccb350b) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- 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-------------------------------- clipboard-202312191405-owvpy.png (27.3 KB) -- https://bugs.ruby-lang.org/

Issue #20043 has been updated by tenderlovemaking (Aaron Patterson). File 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). ---------------------------------------- Bug #20043: `defined?` checks for method existence but only sometimes https://bugs.ruby-lang.org/issues/20043#change-105744 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-12-05T21:25:34Z master 56eccb350b) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- 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-------------------------------- clipboard-202312191405-owvpy.png (27.3 KB) general - ruby-lang - 4 new items - Slack 2023-12-19 16-10-39.png (100 KB) -- https://bugs.ruby-lang.org/

Issue #20043 has been updated by jeremyevans0 (Jeremy Evans). I submitted a pull request to fix this: https://github.com/ruby/ruby/pull/9500 ---------------------------------------- Bug #20043: `defined?` checks for method existence but only sometimes https://bugs.ruby-lang.org/issues/20043#change-106194 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-12-05T21:25:34Z master 56eccb350b) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- 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-------------------------------- clipboard-202312191405-owvpy.png (27.3 KB) general - ruby-lang - 4 new items - Slack 2023-12-19 16-10-39.png (100 KB) -- https://bugs.ruby-lang.org/

Issue #20043 has been updated by ko1 (Koichi Sasada). In future, should we deprecate defined? usecase which return `expression`? ---------------------------------------- Bug #20043: `defined?` checks for method existence but only sometimes https://bugs.ruby-lang.org/issues/20043#change-106902 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-12-05T21:25:34Z master 56eccb350b) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- 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-------------------------------- clipboard-202312191405-owvpy.png (27.3 KB) general - ruby-lang - 4 new items - Slack 2023-12-19 16-10-39.png (100 KB) -- https://bugs.ruby-lang.org/

Issue #20043 has been updated by mame (Yusuke Endoh). Discussed at the dev meeting. @matz 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 said he will investigate the use case in public gem code base. ---------------------------------------- Bug #20043: `defined?` checks for method existence but only sometimes https://bugs.ruby-lang.org/issues/20043#change-108689 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * ruby -v: ruby 3.3.0dev (2023-12-05T21:25:34Z master 56eccb350b) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- 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-------------------------------- clipboard-202312191405-owvpy.png (27.3 KB) general - ruby-lang - 4 new items - Slack 2023-12-19 16-10-39.png (100 KB) -- https://bugs.ruby-lang.org/

Issue #20043 has been updated by ko1 (Koichi Sasada). 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"`. ---------------------------------------- Bug #20043: `defined?` checks for method existence but only sometimes https://bugs.ruby-lang.org/issues/20043#change-108721 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * ruby -v: ruby 3.3.0dev (2023-12-05T21:25:34Z master 56eccb350b) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- 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-------------------------------- clipboard-202312191405-owvpy.png (27.3 KB) general - ruby-lang - 4 new items - Slack 2023-12-19 16-10-39.png (100 KB) -- https://bugs.ruby-lang.org/
participants (7)
-
byroot (Jean Boussier)
-
Dan0042 (Daniel DeLorme)
-
Eregon (Benoit Daloze)
-
jeremyevans0 (Jeremy Evans)
-
ko1 (Koichi Sasada)
-
mame (Yusuke Endoh)
-
tenderlovemaking (Aaron Patterson)