[ruby-core:114713] [Ruby master Bug#17354] Module#const_source_location is misleading for constants awaiting autoload

Issue #17354 has been updated by sawa (Tsuyoshi Sawada). mame (Yusuke Endoh) wrote in #note-11:
2. If we want to identify where a constant is set as autoload, we can use the current `Module#const_source_location`.
If `Module#const_source_location` returns `[]` or `nil` when a constant is not actually loaded, it breaks the scenario 2. In fact I have used the method to identify the callsite of autoload for debugging.
You cannot safely use `const_source_location` (by itself) to extract the autoload call site since the return value depends on whether the constant is called or not: ```rb autoload "A", "path_to_def_of_A" autoload "B", "path_to_def_of_B" p A p Module.const_source_location("A") # => def site p Module.const_source_location("B") # => autoload call site ``` Using `const_source_location`, you can know the call site of `B`, but not the call site of `A`. If you wanted to safely know the autoload call site for a constant name, you would need a different mechanism anyway. Even worse, the return value for the same constant name may change: ```rb autoload "A", File.expand_path("~/tmp/bin/a.rb") p Module.const_source_location("A") # => autoload call site p A p Module.const_source_location("A") # => def site ``` Also, mame suggests to retain the current behavior of `const_source_location` and use it in combination with `autoload?` or `const_get`. That makes `const_source_location` useless by itself, and would have to always be used together with `autoload?` or `const_get` if there is a possibility of autoload. Hence, if there is a use case of extracting the autoload call site as mame discusses, (which I am neither for nor against), there should be a different method for doing that, and `const_source_location` should not return autoload call site at all. ---------------------------------------- Bug #17354: Module#const_source_location is misleading for constants awaiting autoload https://bugs.ruby-lang.org/issues/17354#change-104548 * Author: tomstuart (Tom Stuart) * Status: Open * Priority: Normal * ruby -v: ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin20] * Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN ---------------------------------------- Feature #10771 added `Module#const_source_location` as a way to find the source location of a constant’s definition. Bug #16764 reported that it didn’t work correctly for autoloaded constants, instead giving the source location of the `autoload` call site. This was fixed in `v3_0_0_preview1` in commit:92730810 and backported to `v2_7_2` in commit:c65aae11. However, `#const_source_location` still returns the `autoload` call site for constants which have not yet been loaded: ``` % echo 'class Foo; end' > foo.rb % irb
Module.const_defined?(:Foo) => false Module.const_source_location(:Foo) => nil
autoload :Foo, './foo' => nil
Module.const_defined?(:Foo) => true Module.const_source_location(:Foo) => ["(irb)", 3]
Module.const_get(:Foo) => Foo
Module.const_defined?(:Foo) => true Module.const_source_location(:Foo) => ["./foo.rb", 1]
This edge case is undocumented and surprising. It looks like a bug to the programmer who receives the `autoload` location instead of one of the documented return values of `#const_source_location` (`nil`, `[]`, or the definition’s source location).
We could either:
* change the behaviour of `#const_source_location` to return `[]` for constants awaiting autoload, which is consistent with the [return value of `Module#const_defined?`](https://docs.ruby-lang.org/en/2.7.0/Module.html#method-i-const_defined-3F) in this case (“if the constant is not present but there is an autoload for it, `true` is returned directly”), as well as the [return value of `#const_source_location`](https://docs.ruby-lang.org/en/2.7.0/Module.html#method-i-const_source_location) for other constants whose source location is unknown (“if the constant is found, but its source location can not be extracted (constant is defined in C code), empty array is returned”); or
* document the current behaviour of `#const_source_location` to make it less surprising.
I recommend the first option — although the current behaviour was recently specified in source:spec/ruby/core/module/const_source_location_spec.rb@6d059674#L209, it doesn’t seem intentional — but if that’s not feasible, simply documenting this edge case would also be an improvement.
--
https://bugs.ruby-lang.org/
participants (1)
-
sawa (Tsuyoshi Sawada)