<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="337034" data-post-id="337034">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="mhanberg" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/mhanberg/120/17162_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  mhanberg
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Expert LSP Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<blockquote>
<p>Easier setup, just add dependency like <code>:lib_elixir_1_17_2</code> and then use <code>LibElixir_1_17_2.Code</code> (etc.) instead of having to set up custom config, pre-download, and namespace the abstract forms. (Though that would only happen once.)</p>
</blockquote>
<p>My suggestion is that the package would have all the different versions of Elixir in the same package, so <code>lib_elixir</code> would have say <code>LibElixir.V1_17</code> <code>LibElixir.V1_18</code> in it, so you wouldn’t need to publish new packages for each version.</p>
<blockquote>
<p>More difficult maintainership, or at least more complex setup to get automations in place to distribute multiple lib_elixir versions, stay up-to-date with releases, etc.</p>
</blockquote>
<p>I don’t personally think this would be that difficult, there are like 6 releases of Elixir per year.</p>
<blockquote>
<p>Possibly misusing the hex package registry by encoding the Elixir version in the package name. <code>:lib_elixir_1_17_2</code> instead of <code>:lib_elixir</code>. (This is necessary for different libraries to depend on different versions.)</p>
</blockquote>
<p>Related to my comment above, I don’t think it would be necessary. And to be completely clear, what I mean is that the single package would contain the complete namespaced code for each version of Elixir that is included.</p>
<blockquote>
<p>Doesn’t support building arbitrary ref, e.g. whatever the latest dev build is.</p>
</blockquote>
<p>I think that the use case for this would be limited, but could potentially still include the “inside your project” method originally described. Or potentially a mix task to even vendor in the abstract forms into the users project the same way we would do the library.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="337034" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/working-on-lib-elixir-elixir-core-modules-as-a-library/65316/22">Post #21</a>
	                </div>
	            </div>
              <div id="likers-container-337034" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="337034"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #21"></div>
  </section>
</div>
    <div class="postbit" id="337036" data-post-id="337036">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="zachallaun" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/zachallaun/120/29208_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  zachallaun
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote group-Expert-LSP-Core-Team" data-username="mhanberg" data-post="22" data-topic="65316">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/mhanberg/48/17162_2.png" class="avatar"> mhanberg:</div>
<blockquote>
<p>My suggestion is that the package would have all the different versions of Elixir in the same package, so <code>lib_elixir</code> would have say <code>LibElixir.V1_17</code> <code>LibElixir.V1_18</code> in it, so you wouldn’t need to publish new packages for each version.</p>
</blockquote>
</aside>
<p>Got it – that could work.</p>
<aside class="quote group-Expert-LSP-Core-Team quote-modified" data-username="mhanberg" data-post="22" data-topic="65316">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/mhanberg/48/17162_2.png" class="avatar"> mhanberg:</div>
<blockquote>
<blockquote>
<p>Doesn’t support building arbitrary ref, e.g. whatever the latest dev build is.</p>
</blockquote>
<p>I think that the use case for this would be limited, but could potentially still include the “inside your project” method originally described.</p>
</blockquote>
</aside>
<p>The use-case that comes to mind is test-driving APIs prior to release, but I agree with you that we could likely include both of these mechanisms for selecting a version.</p>
<hr>
<p>One thing I forgot to mention: There is at least one incompatibility that I think was introduced in 1.14 that makes it so that the byte code generated for a lib_elixir 1.14+ can’t be run on less than 1.14 and vice versa, but I think it is possible to address that with another transform to the abstract code.</p>
<p>That can only happen once we know what version of Elixir we’re running, which I was thinking was a point in favor of delaying namespacing, but if it’s really just the one thing, we could bundle both versions of the bytecode and the Mix compiler could “install” the correct ones once it knows what version is running. I’ll need to experiment a bit more.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="337036" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/working-on-lib-elixir-elixir-core-modules-as-a-library/65316/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-337036" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="337036"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #22"></div>
  </section>
</div>
    <div class="postbit" id="337326" data-post-id="337326">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="zachallaun" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/zachallaun/120/29208_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  zachallaun
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’ve made some progress on this, but there are a few things that I wanted to get feedback on. First, a bit of context:</p>
<p>Namespacing currently works by starting with a few user-specified modules like <code>[Code, Macro, ...]</code> and then recursively namespacing those modules and any modules they reference. You’ll get <code>MyNamespace.Code</code>, but you’ll also get <code>MyNamespace.Code.Fragment</code> because <code>Code.Fragment</code> is referenced by <code>Code</code>, and you’ll also get anything that <code>Code.Fragment</code> references, etc.</p>
<p>This can be problematic. As a concrete example, when you parse access syntax like <code>foo[:bar]</code>, you get:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{{:., [line: 1], [Access, :get]}, [line: 1], [{:foo, [line: 1], nil}, :bar]}
</code></pre>
<p>and various tools like Sourceror will look for that <code>[Access, :get]</code> to differentiate between that and <code>Access.get(foo, :bar)</code>, which parses differently.</p>
<p>Without intervention, however, lib_elixir will implicitly namespace <code>Access</code>, so you’d get something like:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{{:., [line: 1], [MyNamespace.Access, :get]}, [line: 1], [{:foo, [line: 1], nil}, :bar]}
</code></pre>
<p>This is problematic because this AST will be misunderstood by other libraries. To address this, lib_elixir has a hard-coded list of excluded modules, including things like <code>Kernel</code>, <code>Access</code>, etc.</p>
<hr>
<p>Given the above, there are certain modules that <em>must</em> be excluded from namespacing, either because module names must be preserved, or for other reasons: <code>String</code>, for instance, is excluded because later versions fail to compile on earlier Elixirs/OTPs.</p>
<p>So I have some thoughts and questions on what and what not to include:</p>
<ol>
<li>
<p>While this idea was introduced as lib_elixir, all of the current intended use-cases make use of only three root modules and their descendants: <code>Code</code>, <code>Macro</code>, and <code>Module</code>. (Though <a class="mention" href="/u/dorgan" rel="nofollow">@dorgan</a> has a use-case for including <code>Mix.Tasks.Format</code> as well.)</p>
<p>As a simplification, should this project explicitly target those modules and be called something like lib_code instead? Are there other modules that people may want to use?</p>
</li>
<li>
<p>Alternatively, should it be the library author’s responsibility to explicitly exclude everything they want excluded? E.g. <code>Access</code> would be namespaced unless you excluded it. Perhaps the only modules that are excluded automatically are those that cannot be included for compatibility reasons, like <code>String</code>?</p>
</li>
<li>
<p>Should transitive dependencies by accessible directly within the namespace? For instance, if you include <code>Code</code>, <code>Code.Fragment</code> could be namespaced as <code>MyNamespace.DEP.Code.Fragment</code> to prevent its accidental use. This also means the <code>Access</code> example above could result in something like <code>{:., [], [MyNamespace.DEP.Access, :get]}</code> depending on the decisions from the above two questions.</p>
</li>
<li>
<p>My personal opinion is that the library should take a strong stance on what’s included and excluded, perhaps with no configuration at all:</p>
<ul>
<li>Rename to lib_code.</li>
<li>Only include modules related to metaprogramming, like <code>Code</code>, <code>Macro</code>, <code>Module</code>, <code>:elixir_tokenizer</code> as it’s used by a number of projects, maybe <code>Mix.Tasks.Format</code>, and their descendants.</li>
<li>Exclude everything not strictly necessary, like <code>Kernel</code>, <code>Access</code>, <code>String</code>, etc.</li>
<li>Munge the names of transitive dependencies that must be included but shouldn’t be used, like <code>Mix.Task</code> (if <code>Mix.Tasks.Format</code> is included), namespacing it as <code>MyNamespace.DEP.Mix.Task</code> or similar.</li>
</ul>
</li>
</ol>
<p>I’d love to hear on the above from folks!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="337326" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/working-on-lib-elixir-elixir-core-modules-as-a-library/65316/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-337326" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="337326"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>