https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112021-03-27T07:58:44ZRuby Issue Tracking SystemRuby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=911142021-03-27T07:58:44Zsawa (Tsuyoshi Sawada)
<ul></ul><p>What would you expect if a module has multiple names?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">E</span><span class="p">;</span> <span class="k">end</span>
<span class="no">E</span><span class="o">::</span><span class="no">F</span> <span class="o">=</span> <span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span>
</code></pre>
<p>Should <code>A::B::C.outer_scope</code> return <code>A::B</code> or <code>E</code>?</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=911182021-03-27T11:33:33ZEregon (Benoit Daloze)
<ul></ul><p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/2963">@sawa (Tsuyoshi Sawada)</a> I'd say first assignment to a named constant wins, just like for Module#name.</p>
<p>I agree with the feature.<br>
I'd suggest <code>Module#namespace</code> for the name though.<br>
For example, I'd say the namespace of <code>Process::Status</code> is <code>Process</code>.</p>
<p><code>scope</code> feels too general to me, and there are many other scopes, so I think namespace is a more precise term for it.</p>
<p><code>namespace</code> is also the term used in <a href="https://github.com/ruby/ruby/blob/master/doc/syntax/modules_and_classes.rdoc#label-Modules" class="external">https://github.com/ruby/ruby/blob/master/doc/syntax/modules_and_classes.rdoc#label-Modules</a></p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=911242021-03-27T21:51:30Ztenderlovemaking (Aaron Patterson)tenderlove@ruby-lang.org
<ul><li><strong>File</strong> <a href="/attachments/8795">0001-Add-Module-namespace.patch</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/8795/0001-Add-Module-namespace.patch">0001-Add-Module-namespace.patch</a> added</li></ul><p>Eregon (Benoit Daloze) wrote in <a href="#note-2">#note-2</a>:</p>
<blockquote>
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/2963">@sawa (Tsuyoshi Sawada)</a> I'd say first assignment to a named constant wins, just like for Module#name.</p>
</blockquote>
<p>Yes, this is what I would expect too (and implemented). 😄</p>
<blockquote>
<p>I agree with the feature.<br>
I'd suggest <code>Module#namespace</code> for the name though.<br>
For example, I'd say the namespace of <code>Process::Status</code> is <code>Process</code>.</p>
</blockquote>
<p>Yes, this is a much better name. I've updated the patch to use "namespace".</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=911322021-03-28T06:05:44Zsawa (Tsuyoshi Sawada)
<ul></ul><p>This feature is reminiscent of <code>Module.nesting</code>. The difference is that the former has dynamic scope and the latter lexical scope. Besides that, I do not see any reason to make them different in any way. What about returning an array of the nested modules (perhaps including self) rather than just the direct parent?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">A</span><span class="p">;</span> <span class="k">module</span> <span class="nn">B</span><span class="p">;</span> <span class="k">class</span> <span class="nc">C</span><span class="p">;</span> <span class="no">Module</span><span class="p">.</span><span class="nf">nesting</span> <span class="k">end</span> <span class="k">end</span> <span class="k">end</span> <span class="c1"># => [A::B::C, A::B, A]</span>
<span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="p">.</span><span class="nf">outer_scope</span> <span class="c1"># => [A::B::C, A::B, A]</span>
</code></pre> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=911342021-03-28T13:33:42Zbyroot (Jean Boussier)byroot@ruby-lang.org
<ul></ul><blockquote>
<p>Besides that, I do not see any reason to make them different in any way</p>
</blockquote>
<p>Well, if <code>Module.nesting</code> because of its scope semantic can't be chained. <code>Module.nesting.nesting</code> would be problematic.</p>
<p>The proposed feature is very easily chainable:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="p">.</span><span class="nf">namespace</span> <span class="c1"># => A::B</span>
<span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="p">.</span><span class="nf">namespace</span><span class="p">.</span><span class="nf">namespace</span> <span class="c1"># => A</span>
</code></pre>
<p>So returning an array doesn't give anything that's not already achievable, and cause an array allocation that some users would rather avoid in some situations.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=913232021-04-05T18:12:57Ztenderlovemaking (Aaron Patterson)tenderlove@ruby-lang.org
<ul><li><strong>Subject</strong> changed from <i>Add Module#outer_scope</i> to <i>Add Module#namespace</i></li></ul> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=914642021-04-10T10:35:48Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>I like the direction this is going towards, however, let me record some remarks for the archives.</p>
<p>Java has namespaces. Ruby does NOT have namespaces. That first sentence in the module docs, also present in books, is a super naive entry point to modules. But it is an abuse of language that later on you should correct.</p>
<p>Ruby does not have syntax for types either.</p>
<p>Ruby has storage (variables, constants, etc.), and objects. That is all, variables, constants, and module objects are totally decoupled except for the fact that you get a name in the first constant assignment. A name that does not reflect the nesting, that is not guaranteed to be unique, that does not mean the object is reachable via that constant path, and that some classes change by overriding the <code>name</code> method. It is just a string.</p>
<p>A library like Zeitwerk or Active Support can take some licenses "you know what I mean" because they are libraries and they work on the assumption of projects structured in a certain way. But a programming language has to be consistent with itself. <code>Module#constants</code> is consistent, in my view <code>Module#namespace</code> is not (with the current model).</p>
<p>So, if Ruby core wants to go in this direction and contribute to normalize a bit the mental model, I am onboard. But we have to be conscious that this is introducing something that is going to leak some way or another.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=914652021-04-10T10:54:19Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>Let me add some edge cases that are possible, also for the archives:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">M</span>
<span class="k">module</span> <span class="nn">N</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">M</span><span class="o">::</span><span class="no">N</span><span class="p">.</span><span class="nf">namespace</span> <span class="c1"># => A::B::C, constant M stores the same object as A::B::C</span>
</code></pre>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">M</span><span class="p">.</span><span class="nf">namespace</span> <span class="c1"># => M, module is namespace of itself</span>
</code></pre>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">M</span><span class="o">::</span><span class="no">N</span><span class="p">.</span><span class="nf">namespace</span> <span class="c1"># => M</span>
<span class="no">M</span><span class="p">.</span><span class="nf">namespace</span> <span class="c1"># => M::N, cycles of arbitrary depth</span>
</code></pre>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">X</span> <span class="o">=</span> <span class="no">M</span><span class="o">::</span><span class="no">N</span>
<span class="c1"># ...</span>
<span class="no">X</span><span class="p">.</span><span class="nf">namespace</span> <span class="c1"># => The module that was once in M has been garbage collected (assuming a weak ref for backwards compat)</span>
</code></pre>
<p>I am sure I can come with more if I think more about it.</p>
<p>The Ruby model of this is extremely flexible and decoupled, and that is the public interface. Constant assignment, constants API, instantiation of anonymous modules, etc.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=914752021-04-10T20:45:34Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>Also, in case my comments above are too generic, let's take the use case in the description of the ticket:</p>
<blockquote>
<p>I can do A::B::C.outer_scope.constants to find the list of "sibling" constants to C.</p>
</blockquote>
<p>Let's consider</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">A</span>
<span class="k">module</span> <span class="nn">B</span>
<span class="k">class</span> <span class="nc">C</span><span class="p">;</span> <span class="k">end</span>
<span class="k">class</span> <span class="nc">D</span><span class="p">;</span> <span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nn">X</span>
<span class="no">Y</span> <span class="o">=</span> <span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span>
<span class="no">Z</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">end</span>
</code></pre>
<p>In what sense is <code>A::B::D</code> a sibling of the class object stored in <code>A::B::C</code> and <code>X::Z</code> is not?</p>
<p>Take now</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">X</span><span class="p">;</span> <span class="k">end</span>
<span class="k">module</span> <span class="nn">Y</span><span class="p">;</span> <span class="k">end</span>
<span class="k">module</span> <span class="nn">Z</span><span class="p">;</span> <span class="k">end</span>
<span class="n">c</span> <span class="o">=</span> <span class="no">Class</span><span class="p">.</span><span class="nf">new</span>
<span class="no">X</span><span class="o">::</span><span class="no">C</span> <span class="o">=</span> <span class="n">c</span>
<span class="no">Y</span><span class="o">::</span><span class="no">C</span> <span class="o">=</span> <span class="n">c</span>
<span class="no">Z</span><span class="o">::</span><span class="no">C</span> <span class="o">=</span> <span class="n">c</span>
</code></pre>
<p>For Ruby, that's all objects and storage, where's <code>c</code> stored has no relevance. It is not different than</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">X</span><span class="p">;</span> <span class="k">end</span>
<span class="k">module</span> <span class="nn">Y</span><span class="p">;</span> <span class="k">end</span>
<span class="k">module</span> <span class="nn">Z</span><span class="p">;</span> <span class="k">end</span>
<span class="no">X</span><span class="o">::</span><span class="no">C</span> <span class="o">=</span> <span class="mi">1</span>
<span class="no">Y</span><span class="o">::</span><span class="no">C</span> <span class="o">=</span> <span class="mi">1</span>
<span class="no">Z</span><span class="o">::</span><span class="no">C</span> <span class="o">=</span> <span class="mi">1</span>
</code></pre>
<p>Yes, <code>c.name</code> is "X::C", but as I said above, that is just a string.</p>
<p>If our input is a class object, as in the <code>ObjectSpace</code> example, you have no information that allows you to jump from it to its possibly multiple places in which the object may be stored. And the original constant may be gone, those places can be elsewhere (as it happens with stale class objects cached during Rails initialization after a reload).</p>
<p>On the other hand, if you are in a very specific situation where you can assume that loop makes sense for all <code>k</code>, you can always <code>name.sub(/::\w+$/, '')</code> and <code>const_get</code>, modulus details. Or you can <code>ObjectSpace.each_object(Module)</code> and inspect constants.</p>
<p>In a project, in a library, you may have constraints in place that you can exploit. In Ruby, the language, you don't.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=914992021-04-12T15:28:30Ztenderlovemaking (Aaron Patterson)tenderlove@ruby-lang.org
<ul></ul><blockquote>
<p>Yes, c.name is "X::C", but as I said above, that is just a string.</p>
</blockquote>
<p>It's also a way to inform the user where that constant lives. The contents of the string have meaning.</p>
<blockquote>
<p>On the other hand, if you are in a very specific situation where you can assume that loop makes sense for all k, you can always name.sub(/::\w+$/, '') and const_get, modulus details.</p>
</blockquote>
<p>This would work if I could trust the <code>name</code> method on a class (I can't, especially in a Rails project).</p>
<p>Of course there are some edge cases with redefinition, but since the "namespace" method would line up with what the "name" method is supposed to return, I think it would be easy to understand the behavior.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=915042021-04-12T17:29:05ZEregon (Benoit Daloze)
<ul></ul><p>I think those edge cases are pretty rare.<br>
Module#namespace would refer to the lexical parent when the module is created (with <code>module Name</code>) or when first assigned to a constant (<code>Name = Module.new</code>).</p>
<p>The first example of <a href="https://bugs.ruby-lang.org/issues/17753#note-8" class="external">https://bugs.ruby-lang.org/issues/17753#note-8</a> would already need extremely contrived code like:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">A</span>
<span class="k">module</span> <span class="nn">B</span>
<span class="k">module</span> <span class="nn">C</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nn">M</span>
<span class="no">N</span> <span class="o">=</span> <span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span>
<span class="k">module</span> <span class="nn">N</span>
<span class="k">end</span>
<span class="nb">p</span> <span class="no">N</span><span class="p">.</span><span class="nf">namespace</span>
<span class="k">end</span>
</code></pre>
<p>and even then the value could still be useful.</p>
<p>In the end, the exact same caveats exist for Module#name and yet it's fine in practice.</p>
<p>A module is a namespace of constants.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=915082021-04-13T09:29:45Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><blockquote>
<p>It's also a way to inform the user where that constant lives. The contents of the string have meaning.</p>
</blockquote>
<p>The numerous people that have had to deal with stale objects in Rails for years know that is not entirely true. The class objects have a name, but that constant path no longer gives you the object at hand, but some another object that happens to have the same name.</p>
<p>Benoit, but a programming language is a formal system. It has to define things that are consistent with its model! It does not matter in my view if the examples are statistically rare. They are only ways to demonstrate the definition does not match the way Ruby works.</p>
<blockquote>
<p>A module is a namespace of constants.</p>
</blockquote>
<p>Yes, but it is dynamic because of const_set and remove_const, and your APIs and concepts need to reflect that.</p>
<p>If you wanted namespaces, you'd have a different programming language where everything is consistent with that concept. But Ruby is not that way.</p>
<p>Same way Ruby does not have types. <code>Admin::User</code> is not a type (we all in this thread know that), it is a constant path. That is all you got, constants and objects, and constants API.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=915092021-04-13T09:37:04Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>BTW, we were discussing yesterday with Aaron that the flag I am raising is about the name <code>namespace</code>. What we are defining given a class object is:</p>
<ol>
<li>If the class object is anonymous, return <code>nil</code>.</li>
<li>Otherwise, it was assigned to a constant at least once. Let <code>namespace</code> be the module object that stored that constant at assignment time if it is an alive object, <code>nil</code> if the original object is gone (possible depending on whether the reference is weak or not).</li>
</ol>
<p>We do not have a good name for that.</p>
<p>Another thing Aaron is exploring is to define <code>Module#namespaces</code>, which would return all modules that store the class object in one of their constants. That is a bit closer to the Ruby model, I believe.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=915102021-04-13T09:46:25Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>To me, the ability of a namespace being namespace of itself</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">m</span> <span class="o">=</span> <span class="no">Module</span><span class="p">.</span><span class="nf">new</span>
<span class="n">m</span><span class="o">::</span><span class="no">M</span> <span class="o">=</span> <span class="n">m</span>
</code></pre>
<p>is one clear indicator that the name is not quite right. That is not the kind of property you expect a namespace to have. And it is not quite right because we are dealing with storage and objects. In the world of storage and objects that example squares perfectly, there is no surprise.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=915112021-04-13T10:01:24Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>Oh, let me say something explicitly: You guys are Ruby committers, you are the ones that have the vision for what makes sense in the language.</p>
<p>I am raising a flag because this does not square to me, and makes me feel it is introducing a leaking abstraction not backed by the language model. It is an abstraction you could tolerate in Active Support with documented caveats, but not one that I personally see in Ruby itself.</p>
<p>However, if once the feedback has been listened to you believe this API squares with your vision of Ruby, by all means go ahead :).</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=915132021-04-13T10:57:11ZEregon (Benoit Daloze)
<ul></ul><p>I see, the name <code>namespace</code> is what we're disagreeing on.<br>
Maybe you have another suggestion for the name of that method?</p>
<p>Maybe <code>outer_module</code>/<code>outer_scope</code> would work too, but I feel <code>namespace</code> is nicer.<br>
All these 3 names imply some kind of lexical relationship. And even though that can be broken, in most cases it is respected and the intent of the user using this new method is clearly to go one step up in the lexical relationship.<br>
So we should mention in the docs this might return unusual results for e.g. anonymous modules that are later assigned to a constant.</p>
<p>FWIW internally that's named "lexical parent module" in TruffleRuby, but that doesn't make a nice method name.<br>
Indeed, it's not always "lexical" but in the vast majority of cases the intent is that and we would say <code>A::B</code> is <code>namespaced</code> or <code>defined under</code> (<code>rb_define_module_under)</code> module/class <code>A</code>.</p>
<p>The way I see it is modules are the closest thing to a namespace that Ruby has. And therefore Module#namespace feels natural to me.<br>
From the other direction, I agree namespaces often have different/stricter semantics than Ruby modules in other languages.<br>
Yet I think it's OK to have a slightly different meaning for namespace in Ruby, and that seems already established in docs.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=915172021-04-13T11:50:57Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>The lexical parent module happens to be just the object from which you set the name, which does not even reflect the scope/nesting at assignment time (as you know):</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">A::B</span>
<span class="k">module</span> <span class="nn">X::Y</span>
<span class="k">class</span> <span class="nc">C</span>
<span class="nb">name</span> <span class="c1"># => "X::Y::C"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>If modules are namespaces, why isn't <code>A::B</code> there?</p>
<p>Yeah, we see it differently. There, I only see a constant assignment. You see it like "most of the time, you can think of it that way because that's how most of Ruby looks like". That difference in points of view is fine :).</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=915272021-04-13T16:35:46Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>BTW, you all know AS has this concept right? <a href="https://github.com/rails/rails/blob/f1e00f00295eb51a64a3008c7b1f4c4f46e902e3/activesupport/lib/active_support/core_ext/module/introspection.rb#L20-L37" class="external">https://github.com/rails/rails/blob/f1e00f00295eb51a64a3008c7b1f4c4f46e902e3/activesupport/lib/active_support/core_ext/module/introspection.rb#L20-L37</a></p>
<p>We say "according to its name", have the <code>X</code> example to clearly see the assumptions, and case closed.</p>
<p>As I said before, AS can take licenses, it is not Ruby itself. And in the context of Rails (the most common case for AS), you can assume some structure.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=915892021-04-17T07:27:29Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul></ul><p>This ticket was discussed on the dev meeting. <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/13">@matz (Yukihiro Matsumoto)</a> said that (1) the use case is not clear to him, and that (2) he wants to keep the keyword <code>namespace</code> for another feature in future. <code>outer_scope</code> is also weird because the return value is not a "scope".</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=915922021-04-17T08:04:41Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>In my view, the way to implement the use case that matches Ruby is to go downwards.</p>
<p>Module has many constants, that is the Ruby model, so instead of</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">ObjectSpace</span><span class="p">.</span><span class="nf">each_object</span><span class="p">(</span><span class="no">Class</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">k</span><span class="o">|</span>
<span class="n">k</span><span class="p">.</span><span class="nf">outer_scope</span><span class="p">.</span><span class="nf">constants</span>
<span class="k">end</span>
</code></pre>
<p>you'd write</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">ObjectSpace</span><span class="p">.</span><span class="nf">each_object</span><span class="p">(</span><span class="no">Module</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">mod</span><span class="o">|</span>
<span class="n">mod</span><span class="p">.</span><span class="nf">constants</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">constant</span><span class="o">|</span>
<span class="c1"># Do something with constant.</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Alternatively, recurse starting at <code>Object</code> (would miss anonymous modules with constants).</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=982552022-07-01T06:52:15Zioquatix (Samuel Williams)samuel@oriontransfer.net
<ul></ul><p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/73">@tenderlovemaking (Aaron Patterson)</a> what about some kind of "uplevel" concept for name:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">A::B::C::MyClass</span><span class="p">;</span> <span class="k">end</span>
<span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="c1"># -> "MyClass"</span>
<span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># -> "C::MyClass"</span>
<span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># -> "A::B::C"</span>
<span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># -> "A::B"</span>
</code></pre>
<p>etc</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=982582022-07-01T16:13:09Zsawa (Tsuyoshi Sawada)
<ul></ul><p>ioquatix (Samuel Williams) wrote in <a href="#note-21">#note-21</a>:</p>
<blockquote>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">A::B::C::MyClass</span><span class="p">;</span> <span class="k">end</span>
<span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="c1"># -> "MyClass"</span>
<span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># -> "C::MyClass"</span>
<span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># -> "A::B::C"</span>
<span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># -> "A::B"</span>
</code></pre>
</blockquote>
<p>What is the rule behind what the argument represents? To me, your four examples except for the first one seem to suggest:</p>
<ol>
<li>The nesting levels (achieved by separating the full name by <code>::</code>) can be referred to by an index as if they were placed in an array.</li>
<li>a. If the argument is negative, then remove the nesting levels from the one indexed by the argument up to the last one.<br>
b. If the argument is non-negative, then remove the nesting levels from the first one up to the one indexed by the argument.</li>
<li>Join the remaining nesting levels with <code>::</code>.</li>
</ol>
<p>But, then I would expect:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="c1"># -> "B::C::MyClass"</span>
</code></pre>
<p>contrary to what you wrote.</p>
<p>What is your intended logic? Is it coherent?</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=982592022-07-02T00:03:51Zioquatix (Samuel Williams)samuel@oriontransfer.net
<ul></ul><pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Class</span>
<span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="n">offset</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
<span class="k">return</span> <span class="k">super</span><span class="p">()</span> <span class="k">unless</span> <span class="n">offset</span>
<span class="n">parts</span> <span class="o">=</span> <span class="k">super</span><span class="p">().</span><span class="nf">split</span><span class="p">(</span><span class="s1">'::'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">offset</span> <span class="o">>=</span> <span class="mi">0</span>
<span class="n">parts</span> <span class="o">=</span> <span class="n">parts</span><span class="p">[(</span><span class="n">parts</span><span class="p">.</span><span class="nf">size</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">offset</span><span class="p">)</span><span class="o">..-</span><span class="mi">1</span><span class="p">]</span>
<span class="k">else</span>
<span class="n">parts</span> <span class="o">=</span> <span class="n">parts</span><span class="p">[</span><span class="mi">0</span><span class="o">...</span><span class="p">(</span><span class="n">parts</span><span class="p">.</span><span class="nf">size</span> <span class="o">+</span> <span class="n">offset</span><span class="p">)]</span>
<span class="k">end</span>
<span class="k">return</span> <span class="n">parts</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s1">'::'</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nn">A</span>
<span class="k">module</span> <span class="nn">B</span>
<span class="k">module</span> <span class="nn">C</span>
<span class="k">class</span> <span class="nc">MyClass</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">pp</span> <span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="c1"># -> "MyClass"</span>
<span class="n">pp</span> <span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># -> "C::MyClass"</span>
<span class="n">pp</span> <span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># -> "A::B::C"</span>
<span class="n">pp</span> <span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># -> "A::B"</span>
</code></pre>
<p>Something like this.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=982602022-07-02T05:01:21Zsawa (Tsuyoshi Sawada)
<ul></ul><p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/3344">@ioquatix (Samuel Williams)</a> (Samuel Williams)</p>
<p>The non-negative part of your code looks pretty much convoluted. To simplify your code (and define it on <code>Module</code> rather than on <code>Class</code>), it would be essentially this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Module</span><span class="p">.</span><span class="nf">prepend</span><span class="p">(</span><span class="no">Module</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="n">offset</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
<span class="k">return</span> <span class="k">super</span><span class="p">()</span> <span class="k">unless</span> <span class="n">offset</span>
<span class="k">super</span><span class="p">().</span><span class="nf">split</span><span class="p">(</span><span class="s1">'::'</span><span class="p">).</span><span class="nf">then</span> <span class="k">do</span>
<span class="k">if</span> <span class="n">offset</span> <span class="o">>=</span> <span class="mi">0</span>
<span class="n">_1</span><span class="p">.</span><span class="nf">last</span><span class="p">(</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">else</span>
<span class="n">_1</span><span class="p">[</span><span class="o">...</span><span class="n">offset</span><span class="p">]</span>
<span class="k">end</span>
<span class="k">end</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s1">'::'</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span><span class="p">)</span>
</code></pre>
<p>This indicates that you are essentially using the argument <code>offset</code>:</p>
<ul>
<li>to specify the <strong>number</strong> of elements when <code>offset</code> is non-negative, and</li>
<li>to specify the ending <strong>position</strong> (index) of the elements otherwise</li>
</ul>
<p>which is incoherent. At least to me, your proposal is in fact difficult to understand because of this. I think it should be unified so that either <code>offset</code> expresses the number all the way down, or it does the position all the way down. Or, perhaps you can limit <code>offset</code> to non-negative.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=982702022-07-03T23:41:52Zioquatix (Samuel Williams)samuel@oriontransfer.net
<ul></ul><p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/2963">@sawa (Tsuyoshi Sawada)</a> Thanks for your feedback and the improved code.</p>
<p>Based on my own needs and other code (see <a href="https://apidock.com/rails/ActiveSupport/Inflector/demodulize" class="external">https://apidock.com/rails/ActiveSupport/Inflector/demodulize</a> and <a href="https://apidock.com/rails/ActiveSupport/Inflector/deconstantize" class="external">https://apidock.com/rails/ActiveSupport/Inflector/deconstantize</a> for example) I see two main use cases:</p>
<p>(1) Get some part of the namespace starting from the left. The most common use case is "The entire module namespace without the class name" but it will also be convenient to cut off more than just the class name in some cases. Since how deeply nested we are is usually not known, cutting from the right hand side makes sense.<br>
(2) Get some part of the class name starting from the right. The most common case is "Just the class name without any module namespace" but it will also be convenient to include some of the nested modules expanding towards the right in some cases.</p>
<p>To me it's consistent within the requirements of solving those two problems and maps nicely to negative and non-negative integers respectively. I realise that between the negative and non-negative offset, there is no continuity but this is by design to satisfy user needs rather than theoretical purity. If you have a better idea, please share it!</p>
<p>In more detail, I don't think this offset should be impacted by changes to module nesting, i.e.</p>
<pre><code># This should be the same:
A::B::C::MyClass.name(1) # C::MyClass
Z::A::B::C::MyClass.name(1) # C::MyClass
# This should always be full module namespace:
A::B::C::MyClass.name(-1) # A::B::C
Z::A::B::C::MyClass.name(-1) # Z::A::B::C
</code></pre>
<p>In addition, user won't know ahead of time the nesting level of the class, and so this proposed interface needs to satisfy the most common use cases without any extra computation, otherwise, user is forced to do string manipulation again. In theory, this proposed interface should also be efficient to implement.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=982722022-07-04T01:42:10Zaustin (Austin Ziegler)halostatue@gmail.com
<ul></ul><p>ioquatix (Samuel Williams) wrote in <a href="#note-25">#note-25</a>:</p>
<blockquote>
<p>To me it's consistent within the requirements of solving those two problems and maps nicely to negative and non-negative integers respectively. I realise that between the negative and non-negative offset, there is no continuity but this is by design to satisfy user needs rather than theoretical purity. If you have a better idea, please share it!</p>
</blockquote>
<p>Since name doesn’t currently accept any arguments, why not make it a keyword instead of a simple integer?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="ss">tail: </span><span class="mi">1</span><span class="p">)</span> <span class="c1"># C::MyClass</span>
<span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="o">::</span><span class="no">C</span><span class="o">::</span><span class="no">MyClass</span><span class="p">.</span><span class="nf">name</span><span class="p">(</span><span class="ss">head: </span><span class="mi">1</span><span class="p">)</span> <span class="c1"># A::B::C</span>
</code></pre>
<p>I don’t know what the name of the keywords should be.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=1017032023-02-08T03:41:49Zshioyama (Chris Salzberg)
<ul></ul><p>This has been quiet for a while, but despite the reservations expressed I'd really like to see it implemented.</p>
<p>I don't personally really like <code>namespace</code> as a name either, because of its usage in other places. It's been mentioned, but what exactly is wrong with <code>Module#module_parent</code>, the same method ActiveSupport uses?</p>
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/1241">@fxn (Xavier Noria)</a></p>
<blockquote>
<p>Yes, c.name is "X::C", but as I said above, that is just a string.</p>
</blockquote>
<p>It's a string, yes, but it also includes some rules about <em>what</em> to return <em>when</em> that I think are relevant to your concerns about edge cases.</p>
<p>I think any implementation of this method should be fully consistent with <code>Module#name</code>. That means also encompassing names that are temporary (where the root is anonymous).</p>
<p>Just so we're all on the same page:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">mod</span> <span class="o">=</span> <span class="no">Module</span><span class="p">.</span><span class="nf">new</span>
<span class="n">mod</span><span class="p">.</span><span class="nf">name</span>
<span class="c1">#=> nil</span>
<span class="n">mod</span><span class="o">::</span><span class="no">Foo</span> <span class="o">=</span> <span class="no">Module</span><span class="p">.</span><span class="nf">new</span>
<span class="n">mod</span><span class="o">::</span><span class="no">Foo</span><span class="p">.</span><span class="nf">name</span>
<span class="c1">#=> "#<Module:0x0000000106471d80>::Foo"</span>
</code></pre>
<p><code>"#<Module:0x0000000106471d80>::Foo"</code> is <code>mod::Foo</code>'s "temporary name". We can assign another module under an anonymous root to it and it will not change:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">other_mod</span> <span class="o">=</span> <span class="no">Module</span><span class="p">.</span><span class="nf">new</span>
<span class="n">other_mod</span><span class="o">::</span><span class="no">Bar</span> <span class="o">=</span> <span class="n">mod</span><span class="o">::</span><span class="no">Foo</span>
<span class="n">other_mod</span><span class="o">::</span><span class="no">Bar</span><span class="p">.</span><span class="nf">name</span>
<span class="c1">#=> "#<Module:0x0000000106471d80>::Foo"</span>
</code></pre>
<p>So temporary names are "sticky" as long as the module doesn't have a permanent name. Once it has a permanent name, that name does not change regardless of assignment to other toplevel-rooted constants.</p>
<p>So we have some rules for how <code>Module#name</code> can and cannot change:</p>
<ol>
<li>A module's permanent name, once assigned, cannot be re-assigned. Although you can nest the same constant in many places in many ways, the <code>name</code>, once the constant has been attached to a permanent root, will not change.</li>
<li>A module's temporary name, once assigned, cannot be re-assigned except to a permanent name. You can assign another constant from an anonymous-rooted namespace, but the module's original temporary name sticks and only changes when/if it gets a permanent name.</li>
</ol>
<p>I think these rules give us everything we need to define a method that returns the immediate parent of a module <em>according to what the <code>name</code> specifies</em>, and I think this would be a very useful method to have.</p>
<p>Extended to anonymous roots, I would expect this (I'm using <code>module_parent</code> here, but replace with whatever name is agreed is best):</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">mod</span> <span class="o">=</span> <span class="no">Module</span><span class="p">.</span><span class="nf">new</span>
<span class="n">mod</span><span class="o">::</span><span class="no">A</span> <span class="o">=</span> <span class="no">Module</span><span class="p">.</span><span class="nf">new</span>
<span class="n">mod</span><span class="o">::</span><span class="no">A</span><span class="o">::</span><span class="no">B</span> <span class="o">=</span> <span class="no">Module</span><span class="p">.</span><span class="nf">new</span>
<span class="n">mod</span><span class="o">::</span><span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="p">.</span><span class="nf">name</span>
<span class="c1">#=> "#<Module:0x0000000109a98fd0>::A::B"</span>
<span class="n">mod</span><span class="o">::</span><span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="p">.</span><span class="nf">module_parent</span>
<span class="c1">#=> #<Module:0x0000000109a98fd0>::A</span>
<span class="n">mod</span><span class="o">::</span><span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="p">.</span><span class="nf">module_parent</span><span class="p">.</span><span class="nf">module_parent</span>
<span class="c1">#=> #<Module:0x0000000109a98fd0></span>
<span class="c1"># Temporary name has been assigned so assigning to</span>
<span class="c1"># another constant rooted in an anonymous module has no impact.</span>
<span class="n">other_mod</span> <span class="o">=</span> <span class="no">Module</span><span class="p">.</span><span class="nf">new</span>
<span class="n">other_mod</span><span class="o">::</span><span class="no">C</span> <span class="o">=</span> <span class="n">mod</span><span class="o">::</span><span class="no">A</span><span class="o">::</span><span class="no">B</span>
<span class="n">other_mod</span><span class="o">::</span><span class="no">C</span><span class="p">.</span><span class="nf">name</span>
<span class="c1">#=> "#<Module:0x0000000109a98fd0>::A::B"</span>
<span class="n">other_mod</span><span class="o">::</span><span class="no">C</span><span class="p">.</span><span class="nf">module_parent</span>
<span class="c1">#=> #<Module:0x0000000109a98fd0>::A</span>
<span class="c1"># Permanent name has been assigned to the root,</span>
<span class="c1"># so both `name` and `module_name` change accordingly</span>
<span class="no">D</span> <span class="o">=</span> <span class="n">mod</span>
<span class="n">mod</span><span class="o">::</span><span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="p">.</span><span class="nf">name</span>
<span class="c1">#=> "D::A::B"</span>
<span class="n">mod</span><span class="o">::</span><span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="p">.</span><span class="nf">module_parent</span>
<span class="c1">#=> D::A</span>
<span class="n">mod</span><span class="o">::</span><span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="p">.</span><span class="nf">module_parent</span><span class="p">.</span><span class="nf">module_parent</span>
<span class="c1">#=> D</span>
<span class="c1"># Giving another permanent name has no impact.</span>
<span class="no">E</span> <span class="o">=</span> <span class="n">mod</span>
<span class="no">E</span><span class="o">::</span><span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="p">.</span><span class="nf">name</span>
<span class="c1">#=> "D::A::B"</span>
<span class="no">E</span><span class="o">::</span><span class="no">A</span><span class="o">::</span><span class="no">B</span><span class="p">.</span><span class="nf">module_parent</span>
<span class="c1">#=> D::A</span>
</code></pre>
<p>This is entirely consistent with how <code>name</code> works, and I think is in fact a very natural complement to it. Since conventions are exactly the same, there is no need for any additional "rules" to cover the edge cases mentioned earlier.</p>
<p>As an implementation, this is fully determined, consistent with an existing pattern (<code>Module#name</code>) and works as expected for most common use cases.</p>
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/18">@mame (Yusuke Endoh)</a></p>
<blockquote>
<p>the use case is not clear to him</p>
</blockquote>
<p>It's been mentioned above, but <a href="https://github.com/rails/rails/blob/dcd8f37bc63d46f28aa55e6891b03a0b0b73e497/activesupport/lib/active_support/core_ext/module/introspection.rb#L39-L62" class="external">ActiveSupport</a> and other libraries use <code>mod.name.split("::")</code> all over the place to go from something they can <em>see</em> (<code>Module#name</code>) to something they can <em>use</em> (actual module objects). This has always seemed extremely clumsy to me; Ruby generated the <code>name</code> from the module objects, but it will only give you the "trace" of them, not the actual living things.</p>
<p>Personally, I've been recently working with anonymous-rooted namespaces (like <code>mod</code> and <code>mod::Foo</code> above) and the inability to get the root of a module is yet more problematic, because <code>name.split("::")</code> and <code>constantize</code> don't work in that context. I'd love to see this happen, under any name that seems appropriate.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=1017092023-02-08T07:54:51Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>Yeah, I believe the feature makes sense and can be useful, and the proposed implementation that keeps a pointer is well-defined (vs what AS does). Also consistent with <code>Module#name</code>, as you said.</p>
<p>My observations above were more related to the name <code>namespace</code> I think, because we are defining "the class or module object that holded the constant to which I was initially assigned, if any". That is weaker.</p>
<p>Regarding your proposal, in English would be <code>parent_module</code> right?</p>
<p>Let me add something, this is practical, but the Ruby model suffers just a little bit in my view. Let me explain.</p>
<p>To me:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">M</span>
<span class="no">X</span> <span class="o">=</span> <span class="no">String</span><span class="p">.</span><span class="nf">new</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nn">N</span>
<span class="no">X</span> <span class="o">=</span> <span class="no">Module</span><span class="p">.</span><span class="nf">new</span>
<span class="k">end</span>
</code></pre>
<p>are essentially the same, Ruby objects stored in places. As we all know, the Ruby model is quite unconstrained, which makes it beautiful, but also weaker in a logical sense.</p>
<p>So, there is a part of me that believes for consistency the string object should also respond to <code>parent_module</code>, which is a weird derivation. (I am playing reductio at absurdum here, no proposing that!).</p>
<p>However, maybe in this case practicality can win over a pure and spherical language model, I don't know :).</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=1017172023-02-08T10:01:56Zfxn (Xavier Noria)fxn@hashref.com
<ul></ul><p>Let me reword that last remark about "the Ruby model suffers just a little bit".</p>
<p>Ruby objects and variables behave the same. But constants are not as orthogonal and generic:</p>
<ol>
<li>When you assign an integer to a constant, it's just storage. If you assign a class or module object with a name, it's just storage. However, assigning an anonymous class or module object changes the state, it has a side-effect that is only programmed for these objects.</li>
<li>The <code>class</code> and <code>module</code> keywords perform constant assignments.</li>
</ol>
<p>So, "suffer" is not an exact word for what I have in mind. I'd say this change would <em>accentuate</em> an already existing asimmetry, and in a way that is consitent with <code>Module#name</code>. This is not bad, it goes in a consistent direction.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=1017302023-02-09T08:02:48Zshioyama (Chris Salzberg)
<ul></ul><blockquote>
<p>When you assign an integer to a constant, it's just storage. If you assign a class or module object with a name, it's just storage. However, assigning an anonymous class or module object changes the state, it has a side-effect that is only programmed for these objects.</p>
</blockquote>
<p>That's a very interesting way to put it, I hadn't thought of it that way. And indeed those side-effects scale with the number of other classes and modules rooted in the thing that was named.</p> Ruby master - Feature #17753: Add Module#namespacehttps://bugs.ruby-lang.org/issues/17753?journal_id=1017572023-02-10T00:48:49Zshioyama (Chris Salzberg)
<ul></ul><blockquote>
<p>Regarding your proposal, in English would be <code>parent_module</code> right?</p>
</blockquote>
<p>My interpretation here, but to me "parent module" would signify the "parent thing that is a module" of the current thing (whatever that thing may be), whereas "module parent" would signify the "module's parent", implying the <em>parent</em> could be anything (but kind of implying it is also a module).</p>
<p>English-wise as a method name either is possible, they just have slightly different emphasis. I suggested <code>module_parent</code> because it exists and is being used for the same thing, so there's a precedent, which might make it easier to agree on.</p>