https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112022-03-10T16:13:02ZRuby Issue Tracking SystemRuby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=967612022-03-10T16:13:02ZEregon (Benoit Daloze)
<ul><li><strong>Related to</strong> <i><a class="issue tracker-2 status-5 priority-4 priority-default closed" href="/issues/11547">Feature #11547</a>: remove top-level constant lookup</i> added</li></ul> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=967622022-03-10T16:23:11ZNuriYuri (Youri Nouri)
<ul></ul><p>I always believed it was expected because ConstantSpecs.const_get("ConstantSpecsTwo::Foo") behave like:</p>
<pre><code>module ConstantSpecs
p ConstantSpecsTwo::Foo
end
</code></pre>
<p>If you call <code>ConstantSpecs.const_get("ConstantSpecsTwo::Foo", false)</code> it'll be equivalent to <code>ConstantSpecs::ConstantSpecsTwo::Foo</code>.</p>
<pre><code>ConstantSpecs.const_get("ConstantSpecsTwo::Foo", false)
# => (irb):8:in `const_get': uninitialized constant ConstantSpecs::ConstantSpecsTwo (NameError)
</code></pre> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=967692022-03-10T17:58:12ZEregon (Benoit Daloze)
<ul></ul><p>NuriYuri (Youri Nouri) wrote in <a href="#note-2">#note-2</a>:</p>
<blockquote>
<p>I always believed it was expected because ConstantSpecs.const_get("ConstantSpecsTwo::Foo") behave like:</p>
</blockquote>
<p>Interesting, I didn't think of it like that, but I can see that point of view.<br>
The thing there is that code has a lookup nesting of <code>[ConstantSpecs, Object]</code> (<code>Module.nesting</code> doesn't show Object but it's there internally).</p>
<blockquote>
<p>If you call <code>ConstantSpecs.const_get("ConstantSpecsTwo::Foo", false)</code> it'll be equivalent to <code>ConstantSpecs::ConstantSpecsTwo::Foo</code>.</p>
</blockquote>
<p>Not really because lexical lookup does look in the ancestor chains, while that does not (but unused for this example).<br>
e.g. <code>class D; A=:f; end; class C < D; p A; end; p C::A</code> works and prints <code>:f</code> twice.</p>
<hr>
<p>IMHO the problematic/inconsistent/surprising behavior is this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Enumerable</span><span class="p">.</span><span class="nf">const_get</span><span class="p">(</span><span class="ss">:Process</span><span class="p">)</span> <span class="c1"># => Process, BAD</span>
<span class="no">Enumerable</span><span class="o">::</span><span class="no">Process</span> <span class="c1"># => uninitialized constant Enumerable::Process (NameError), GOOD</span>
<span class="no">Object</span><span class="p">.</span><span class="nf">const_get</span><span class="p">(</span><span class="s2">"Enumerable::Process"</span><span class="p">)</span> <span class="c1"># => uninitialized constant Enumerable::Process (NameError), GOOD</span>
</code></pre>
<p>i.e., it seems very similar to the pitfall explained in <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: remove top-level constant lookup (Closed)" href="https://bugs.ruby-lang.org/issues/11547">#11547</a>.</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=967892022-03-11T18:56:24Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>I do not know which is the correct definition of <code>const_get</code>, Ruby core knows :).</p>
<p>However, let me say that I have always thought about <code>const_get</code> as what happens during a <em>relative</em> constant lookup. That is, in my mind, a relative constant lookup is basically: 1) Check the nesting + 2) <code>const_get</code>.</p>
<p>Take for example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Module</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">const_get</span><span class="p">(</span><span class="ss">:String</span><span class="p">)</span> <span class="c1"># => String</span>
</code></pre>
<p>You get <code>String</code> there, but it is not in the ancestors. Why? Because it is checking <code>Object</code> by hand, since the receiver is a module, like the relative constant lookup algorithm does.</p>
<p>I believe</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">String</span><span class="p">.</span><span class="nf">const_get</span><span class="p">(</span><span class="ss">:Hash</span><span class="p">)</span> <span class="c1"># => Hash</span>
</code></pre>
<p>has to be understood that way.</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=968182022-03-13T09:49:46ZNuriYuri (Youri Nouri)
<ul></ul><p>If the current definition is correct, could we add as a feature an additional lookup parameter (or method) that says "do not lookup in Object" so we can get a sort of <code>Module.const_get(:Constant)</code> strictly equivalent to <code>Module::Constant</code>. (I believe I also have cases like that and it's not practical to have to do <code>Object.const_get("#{module_to_look_up}::#{const_to_lookup}")</code>...)</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=968192022-03-13T10:03:52Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>It would not be enough.</p>
<p>When you do a relative constant lookup in which the cref is a module, <code>Object</code> is checked by hand before calling <code>const_missing</code>. Take for example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">M</span>
<span class="no">String</span>
<span class="k">end</span>
</code></pre>
<p>Why is <code>String</code> found there? It is not in the nesting. It is not in the ancestors. So? Ruby checks <code>Object</code> by hand and finds it there.</p>
<p>But, Ruby does not check <code>Object</code> by hand in constant paths:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">M</span><span class="o">::</span><span class="no">String</span> <span class="c1">#=> NameError</span>
</code></pre>
<p>However,</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">M</span><span class="p">.</span><span class="nf">const_get</span><span class="p">(</span><span class="ss">:String</span><span class="p">)</span> <span class="c1">#=> String</span>
</code></pre>
<p>My point is that <code>const_get</code> implements the logic used in relative constant lookups. And in that point of view, checking <code>Object</code> is not an inconsistency or bug, but expected.</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=968202022-03-13T12:08:07ZEregon (Benoit Daloze)
<ul></ul><p>fxn (Xavier Noria) wrote in <a href="#note-6">#note-6</a>:</p>
<blockquote>
<p>Why is <code>String</code> found there? It is not in the nesting. It is not in the ancestors. So? Ruby checks <code>Object</code> by hand and finds it there.</p>
</blockquote>
<p>Actually I'd argue it's in the nesting (just not shown by <code>Module.nesting</code>), the outermost (implicit) "root" lexical constant scope is always Object (and in fact it's implemented that way in TruffleRuby, maybe in CRuby too).<br>
What's special about this root scope is it's checked after the ancestors of the innermost module (and so for classes there is no need as Object is in their ancestors, but for modules that's not the case).</p>
<p>From the implementation POV, about half of usages look in Object and the other half not, I'm not sure there is a general rule for it, it seems a bit ad-hoc currently.<br>
Maybe the rule is if we're looking after a <code>::</code> then don't look in Object but otherwise do?<br>
And <code>A.const_get(:B)</code> is not considered like <code>A::B</code> but like <code>module A; B; end</code>?</p>
<p>This issue is mostly about do we still need to look in Object, in which cases, and could there be simpler overall rules for the various constant lookups?</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=968212022-03-13T12:34:54Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><blockquote>
<p>Actually I'd argue it's in the nesting (just not shown by Module.nesting), the outermost (implicit) "root" lexical constant scope is always Object (and in fact it's implemented that way in TruffleRuby, maybe in CRuby too).</p>
</blockquote>
<p>I believe that is confounding the contract with your implementation.</p>
<p>From the POV of the programmer, <code>Module.nesting</code> tells you the nesting, <code>Object</code> is not in the nesting. Relative constant lookup checks first the nesting, if not found there, then you check the ancestors. If not found there, and the cref is a module, you additionally check <code>Object</code></p>
<p>This is consistent with what Flanagan & Matz says on page 261:</p>
<blockquote>
<p>Ruby first attempts to resolve a constant in the lexical scope of the reference. This means that it first checks the class or module that encloses the constant reference to see if that class or module defines the constant. If not, it checks the next enclosing class or module. This continues until there are no more classes or modules. Note that top-level or "global" constants are not considered part of the lexical scope and are not considered during this part of constant lookup. The class method Module.nesting returns the list of classes and modules that are searched in this step, in the order they are searched.</p>
</blockquote>
<blockquote>
<p>If no constant definition is found in the lexically closing scope, Ruby next tries to resolve the constant in the inheritance hierarchy by checking the ancestors of the class or module that referred to the constant.</p>
</blockquote>
<blockquote>
<p>If no constant definition is found in the inheritance hierarchy, then top-level constant definitions are checked.</p>
</blockquote>
<p>Now, I don't know how TruffleRuby <em>implements</em> lookup, but I am pretty certain <code>Object</code> does not belong to the nesting, and that the public contract, conceptually, is that one.</p>
<blockquote>
<p>And A.const_get(:B) is not considered like A::B but like module A; B; end?</p>
</blockquote>
<p>This is what I am trying to say in my previous comments. And that is why looking at <code>Object</code> is not inconsistent. What happens in <code>A::B</code> is not relevant for <code>const_get</code>.</p>
<blockquote>
<p>This issue is mostly about do we still need to look in Object, in which cases, and could there be simpler overall rules for the various constant lookups?</p>
</blockquote>
<p>You look at <code>Object</code> by hand, because people expect <code>String</code> to be available everywhere (except in <code>BasicObject</code>, which is an edge case). So, whether the ancestors have <code>Object</code> or not is a technicality, from the POV of the user, you want <code>module M; String; end</code> to work. And that means you need to introduce a special rule for modules.</p>
<p>Personally, I think the lookup is pretty intuitive and easy to understand once documented.</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=968222022-03-13T12:52:19Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>For completeness, let me add that that the described lookup is incomplete. Like all the lookup descriptions I've seen, it obviates <code>Module#autoload</code>. Also, the nesting is not strictly lexical. You can push an anonymous module to the nesting of a script with</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">load</span> <span class="n">script</span><span class="p">,</span> <span class="kp">true</span>
</code></pre>
<p>also, you can push an arbitrary class or module to the nesting with</p>
<pre><code>A::B::C.eval_family_of_methods(STRING)
</code></pre>
<p>In any case, my conclusion is that <code>const_get</code> does what it is supposed to do. It is not inconsistent.</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=968232022-03-13T12:53:24ZEregon (Benoit Daloze)
<ul></ul><p>That makes sense, I think we should improve <code>const_get</code> docs to says it's like <code>module A; B; end</code> and not <code>A::B</code> (which I'd think I'm not the only one to assume).</p>
<p>For example I think it's nice to be able to implement <code>mod.const_lookup("B::C")</code> (i.e., before const_get handled <code>::</code> paths) as <code>path.split('::').inject(mod) { _1.const_get(_2) }</code> but that's actually not fully equivalent.</p>
<p>Regarding Object in the nesting, I feel it's consistency with the general situation for the top-level:</p>
<ul>
<li>
<code>default definee</code>: Object (clearly the case)</li>
<li>
<code>self</code>: main, an Object (clearly the case)</li>
<li>
<code>cref</code>: Object (clearly the case, but that's not same as being in the nesting unfortunately)</li>
</ul>
<p>So the top-level is very similar to:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Object</span>
<span class="kp">private</span>
<span class="nb">self</span> <span class="o">=</span> <span class="n">main</span> <span class="c1"># not instance_eval, that would change the default definee</span>
<span class="o"><</span><span class="n">source</span> <span class="n">code</span><span class="o">></span>
<span class="k">end</span>
</code></pre>
<p>But indeed with more subtleties for constant lookup so <code>Object</code> is looked last, after the module/class's ancestors.</p>
<p>I wish we could model constant lookup with just a nesting and have the invariant <code>cref == nesting.first</code>, but that doesn't hold for the top-level (AFAIK only for that case), unless the root constant scope is treated specially (as it is in TruffleRuby, and as we see the top-level constant scope is also special semantically anyway).</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=968242022-03-13T13:55:41Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><blockquote>
<p>That makes sense, I think we should improve const_get docs to says it's like module A; B; end and not A::B (which I'd think I'm not the only one to assume).</p>
</blockquote>
<p>Agree :). The documentation of the constants API has a lot of room for improvement. Also, lookup algorithms, you basically need to reverse engineer them (or read source code). I remember some 10 years ago in Amsterdam, talking about this, that <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/286">@headius (Charles Nutter)</a> told me: "You are going through what I had to go through myself to implement JRuby".</p>
<p>I documented quite a bit in the old Rails guide (<a href="https://guides.rubyonrails.org/v5.2/autoloading_and_reloading_constants.html#constants-refresher" class="external">https://guides.rubyonrails.org/v5.2/autoloading_and_reloading_constants.html#constants-refresher</a>), because in order to understand the caveats of the old system, users had to understand how things work. Still, not a spec, the full precise details would not fulfill that didactic goal.</p>
<p>However, let me add a nuance. The current documentation says:</p>
<blockquote>
<p>Checks for a constant with the given name in mod. If inherit is set, the lookup will also search the ancestors (and Object if mod is a Module).</p>
</blockquote>
<p>Therefore, it is implicitly saying it is not mimicking <code>A::B</code>, because <code>A::B</code> does not check <code>Object</code> and does not check modules by hand.</p>
<p>But I agree with you, this could be more clear.</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=973482022-04-21T06:53:16Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>For the sake of consistency, it is nice to start searching from the receiver class/module. I really like to fix the behavior, if there's no compatibility issue.<br>
But in reality, changing the behavior possibly affect numerous usage of <code>const_get</code> (4000+ appearance by gem search).<br>
I am not sure this consistency really worth the possible compatibility issues.</p>
<p>Matz.</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=973772022-04-21T15:22:36Zaustin (Austin Ziegler)halostatue@gmail.com
<ul></ul><p>matz (Yukihiro Matsumoto) wrote in <a href="#note-12">#note-12</a>:</p>
<blockquote>
<p>For the sake of consistency, it is nice to start searching from the receiver class/module. I really like to fix the behavior, if there's no compatibility issue.<br>
But in reality, changing the behavior possibly affect numerous usage of <code>const_get</code> (4000+ appearance by gem search).<br>
I am not sure this consistency really worth the possible compatibility issues.</p>
</blockquote>
<p>I think it would be worth an experimental flag, TBH. I have a few places where I am calling <code>const_get</code> in some gems and my <em>intent</em> is just to search in the space where I am (if bare) or in the receiver class/module (if the receiver is explicit).</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=973782022-04-21T15:30:55Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>I you want to check only in the receiver, that is <code>mod.const_get(cname, false)</code> already.</p>
<p>If you want to check from the receiver up the ancestors chain, that is <code>mod.const_get(cname)</code> already.</p>
<p>If the receiver is a module, and the constant is not found in the ancestors the method checks <code>Object</code> manually as it happens in relative constant lookups. This is documented.</p>
<p>So, a relative constant lookup could be seen as checking the nesting + <code>const_get</code> + <code>const_missing</code>. This is how I see <code>const_get</code> and in that sense I am personally fine with the current behavior.</p>
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/772">@Eregon (Benoit Daloze)</a> opened this issue because for him, the manual check in <code>Object</code> is surprising (conceptually, regardless of documentation).</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=973912022-04-22T02:08:34Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul></ul><p>FYI: Here is an example that will be affected by the proposed change</p>
<p><a href="https://github.com/googleapis/google-cloud-ruby/blob/367ca0d9c3e7a9a972c367670e56439ff49b8d18/google-cloud-retail-v2/lib/google/cloud/retail/v2/search_service/client.rb#L64" class="external">https://github.com/googleapis/google-cloud-ruby/blob/367ca0d9c3e7a9a972c367670e56439ff49b8d18/google-cloud-retail-v2/lib/google/cloud/retail/v2/search_service/client.rb#L64</a></p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="n">namespace</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"Google"</span><span class="p">,</span> <span class="s2">"Cloud"</span><span class="p">,</span> <span class="s2">"Retail"</span><span class="p">,</span> <span class="s2">"V2"</span><span class="p">]</span>
<span class="n">parent_config</span> <span class="o">=</span> <span class="k">while</span> <span class="n">namespace</span><span class="p">.</span><span class="nf">any?</span>
<span class="n">parent_name</span> <span class="o">=</span> <span class="n">namespace</span><span class="p">.</span><span class="nf">join</span> <span class="s2">"::"</span>
<span class="n">parent_const</span> <span class="o">=</span> <span class="nb">const_get</span> <span class="n">parent_name</span>
<span class="k">break</span> <span class="n">parent_const</span><span class="p">.</span><span class="nf">configure</span> <span class="k">if</span> <span class="n">parent_const</span><span class="p">.</span><span class="nf">respond_to?</span> <span class="ss">:configure</span>
<span class="n">namespace</span><span class="p">.</span><span class="nf">pop</span>
<span class="k">end</span>
</code></pre> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=973952022-04-22T09:46:27ZEregon (Benoit Daloze)
<ul></ul><p>The fix of that would be to use <code>Object.const_get parent_name</code> instead of <code>const_get parent_name</code>, or to use <code>const_get "::#{parent_name}</code>.<br>
The current code seems rather fragile and would break if there is any nested Google module for instance (with so many nested namespaces it does not sound too unlikely).</p>
<p>I'm unsure how much code this change would break.<br>
It might also help reveal and avoid bugs with similar cases as shown in <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: remove top-level constant lookup (Closed)" href="https://bugs.ruby-lang.org/issues/11547">#11547</a>.<br>
One way to get an idea would be to make a PR, test a few popular gems locally to see if they work or not.<br>
If that does not reveal too many issues, I think the best would be to emit a deprecation warning for one or a few versions when going through the special Object lookup for a module, and then in a later version actually remove that extra lookup.</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=973972022-04-22T10:38:01Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/772">@Eregon (Benoit Daloze)</a> in your proposal</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Module</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">const_get</span><span class="p">(</span><span class="ss">:String</span><span class="p">)</span>
</code></pre>
<p>raises.</p>
<p>Would</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Class</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">const_get</span><span class="p">(</span><span class="ss">:String</span><span class="p">)</span>
</code></pre>
<p>raise as well like <code>mod::String</code> does for <code>mod != Object</code>?</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=973982022-04-22T11:06:47ZEregon (Benoit Daloze)
<ul></ul><p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/1241">@fxn (Xavier Noria)</a> A good point, it applies both to module and classes, it seems <code>mod::Name</code> always ignores constants of Object, whether mod is module or class.</p>
<p>I'd like <code>A.const_get("B::C")</code> to behave exactly the same as <code>A::B::C</code>.<br>
That also has the nice property that <code>A.const_get("B::C")</code> = <code>A::B.const_get("C")</code> = <code>A.const_get("B").const_get("C")</code>.</p>
<p>If we compare to literal <code>::</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Class</span><span class="p">.</span><span class="nf">new</span><span class="o">::</span><span class="no">String</span> <span class="c1"># => uninitialized constant #<Class:0x0000000001b98330>::String (NameError)</span>
<span class="no">Class</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">const_get</span> <span class="ss">:String</span> <span class="c1"># => String currently, but I'd like NameError</span>
<span class="no">Module</span><span class="p">.</span><span class="nf">new</span><span class="o">::</span><span class="no">String</span> <span class="c1"># => uninitialized constant #<Module:0x00000000019456f0>::String (NameError)</span>
<span class="no">Module</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">const_get</span> <span class="ss">:String</span> <span class="c1"># => String currently, but I'd like NameError</span>
</code></pre>
<p>So <code>::</code> doesn't look into <code>Object</code> (<code>String</code> is a constant of <code>Object</code>) (since <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: remove top-level constant lookup (Closed)" href="https://bugs.ruby-lang.org/issues/11547">#11547</a> I think).<br>
In other words, with <code>::</code> classes do look into ancestors <em>except for Object</em>, and modules only look in their own ancestors (which never include <code>Object</code>).<br>
That only applies to <code>Object</code> itself, <code>Kernel</code> constants for instance are considered simply whether they are in the ancestors or not.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">Kernel</span><span class="p">;</span> <span class="no">K</span> <span class="o">=</span> <span class="ss">:kernel</span><span class="p">;</span> <span class="k">end</span>
<span class="no">Class</span><span class="p">.</span><span class="nf">new</span><span class="o">::</span><span class="no">K</span> <span class="c1"># => :kernel</span>
<span class="no">Class</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">const_get</span> <span class="ss">:K</span> <span class="c1"># => :kernel</span>
<span class="no">Module</span><span class="p">.</span><span class="nf">new</span><span class="o">::</span><span class="no">K</span> <span class="c1"># => uninitialized constant #<Module:0x0000000001e7ba20>::K (NameError)</span>
<span class="no">Module</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">const_get</span> <span class="ss">:K</span> <span class="c1"># => :kernel currently, but I'd like NameError</span>
<span class="no">Module</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">include</span><span class="p">(</span><span class="no">Kernel</span><span class="p">)</span><span class="o">::</span><span class="no">K</span> <span class="c1"># => :kernel</span>
<span class="no">Module</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">include</span><span class="p">(</span><span class="no">Kernel</span><span class="p">).</span><span class="nf">const_get</span> <span class="ss">:K</span> <span class="c1"># => :kernel</span>
</code></pre>
<p>I think I also understand better your relative and absolute lookups terms now.<br>
In <code>A::B::C</code>, <code>A</code> is a relative lookup/scope lookup/nesting lookup.<br>
And <code>B</code> and <code>C</code> are both using "absolute lookup"/"only ancestors and always ignoring constants of Object to avoid going back to the root scope inadvertently".</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=973992022-04-22T11:26:07Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>Exactly :).</p>
<p>Backwards compatibility, adding a flag, a new method, etc., is something for core to consider. But in any case, I like your proposal.</p> Ruby master - Bug #18622: const_get still looks in Object, while lexical constant lookup no longer doeshttps://bugs.ruby-lang.org/issues/18622?journal_id=1042832023-08-24T17:31:31Zjeremyevans0 (Jeremy Evans)merch-redmine@jeremyevans.net
<ul></ul><p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/13">@matz (Yukihiro Matsumoto)</a> This was reviewed during the June 2023 developer meeting and is still waiting for your response: <a href="https://github.com/ruby/dev-meeting-log/blob/master/2023/DevMeeting-2023-06-08.md#bug-18622-const_get-still-looks-in-object-while-lexical-constant-lookup-no-longer-does-jeremyevans0" class="external">https://github.com/ruby/dev-meeting-log/blob/master/2023/DevMeeting-2023-06-08.md#bug-18622-const_get-still-looks-in-object-while-lexical-constant-lookup-no-longer-does-jeremyevans0</a></p>