<p>The only way that I know how <code>import</code> statements could be implemented is in the parsing stage where the imported module's <code>AST</code> is directly concatenated onto the main script's <code>AST</code> and the variables from the imported file are added to the main Symbol Table.</p>
<p>I wanted to know if this method is suitable for a production language, as it seems rather simplistic and does not take into account things like namespaces and access modifiers. Is there any advantage of doing it this way? Do any other languages just insert the AST into the main file?</p>
<p>If not, what other ways can this be implemented, regardless of import semantics, and how have other languages done it? What might the differences in implementation be in a dynamic language, like Python, vs a static language, like Rust?</p>
<p>If possible, could you please point to some links/implementations on GitHub?</p>

<implementation><imports>
What are the different ways import statements can be implemented?
CC BY-SA 4.0
2023-05-18T16:31:50.017Z
This assumes you're performing identifier resolution at compile time. If your languages defers scope until runtime (such as Python), then you don't add anything to the symbol table.
chrisaycock
CC BY-SA 4.0
2023-05-18T16:39:08.837Z
Possible duplicate of [What are the different ways of handling imports?](https://languagedesign.stackexchange.com/questions/313/what-are-the-different-ways-of-handling-imports)
pppery
CC BY-SA 4.0
2023-05-18T16:48:25.770Z
@pppery That question is about the possible semantics of import declarations or statements; this question is about the implementation of import statements.
kaya3
CC BY-SA 4.0
2023-05-19T04:16:16.713Z
@user16217248 As I said, the other question is about possible semantics and this one is about implementation of one of those semantics. I don't see how it's unclear.
kaya3
CC BY-SA 4.0
2023-05-19T07:12:15.530Z
For the languages where imports are resolved at runtime, are you asking about the implementation of the runtime resolution? Or about attempts to do resolution statically for things like developer tooling? Or both?
starball
CC BY-SA 4.0
2023-05-19T07:15:06.570Z
More about the implementation of resolution
FireTheLost
<h1>#include</h1>
<p>Some languages, like C, C++, and Lua (partially), literally just copy-paste the imported file into the current file. This may have a propensity for making huge files and long compilation times, but it’s the simplest way that works.</p>

CC BY-SA 4.0
2023-05-18T13:38:32.770Z
2023-05-23T16:23:01.537Z
2023-05-23T16:23:01.537Z
Seggan
CC BY-SA 4.0
2023-05-23T16:19:51.957Z
Lua doesn't work this way exactly; the `require` function will only import the required script once. It will also return its return value, if any. [Reference.](https://www.lua.org/pil/8.1.html)
124816
<p>Here's how a modern dynamic language like Python might do it. Assume the interpreter maintains a cache of loaded modules, indexed either by the module name, filesystem path, or some other unique identifier.</p>
<ul>
<li>If the module already exists in the cache, return the cached object.</li>
<li>Locate and open the appropriate source file for the imported module. If there is no such module, raise an error.</li>
<li>Insert an empty object for the module into the cache. (This marks the module's state as &quot;in progress&quot; and prevents unbounded recursion if there is a cyclic import.)</li>
<li>Recursively interpret the source file (i.e. invoke the interpreter's function for executing a source file).</li>
<li>Update the cache by adding the module's exported members to the object representing the imported module.</li>
<li>Bind the object or its imported members to the appropriate name(s) in the current scope.</li>
</ul>
<hr />
<p>The above might be difficult to follow, so here's an example. Suppose we have three files:</p>
<pre class="lang-python prettyprint-override"><code># foo.py
import bar
from baz import y
print(bar.x, y)

# bar.py
import baz
x = baz.y + 2

# baz.py
y = 3
</code></pre>
<p>We begin executing the program <code>foo.py</code>. Suppose <code>Module</code> is a class used to represent modules internally.</p>
<ul>
<li>The first statement is <code>import bar</code>, so we locate and open <code>bar.py</code>, add <code>bar: Module()</code> to the cache, and begin executing the source in that file.
<ul>
<li>The first statement is <code>import baz</code>, so we locate and open <code>baz.py</code>, add <code>baz: Module()</code> to the cache, and begin executing the source in that file.
<ul>
<li>The statement <code>y = 3</code> binds the name <code>y</code> to the value <code>3</code>.</li>
</ul>
</li>
<li>The property <code>y: 3</code> is added to the module object associated with the name <code>'baz'</code>.</li>
<li>The module object <code>{y: 3}</code> from the cache is bound to the name <code>baz</code>.</li>
<li>The statement <code>x = baz.y</code> accesses the <code>y</code> property from the module object <code>baz</code>, and binds the name <code>x</code> to the value <code>5</code>.</li>
</ul>
</li>
<li>The properties <code>x: 5</code> and <code>baz: {y: 3}</code> are added to the module object associated with the name <code>'bar'</code>.</li>
<li>The module object <code>{x: 5, baz: {y: 3}}</code> from the cache is bound to the name <code>bar</code>.</li>
<li>The second statement is <code>from baz import y</code>, and <code>'baz'</code> is already in the cache, so we find the module object <code>{y: 3}</code> associated with it, and bind the name <code>y</code> to the value <code>3</code>.</li>
<li>The final statement <code>print(bar.x, y)</code> reads the <code>x</code> property from the module object <code>{x: 5, baz: {y: 3}}</code>, and hence prints <code>5 3</code>.</li>
</ul>
<hr />
<blockquote>
<p>it seems rather simplistic and does not take into account things like namespaces and access modifiers</p>
</blockquote>
<p>It does take into account namespaces ─ notice how a simple import statement like <code>import bar</code> binds the name <code>bar</code> to a module object which serves a namespace for <code>bar</code>'s exported members. Moreover, since <code>bar.py</code> exports the <code>baz</code> module object, this could be accessed in <code>foo.py</code> as <code>bar.baz.y</code>.</p>
<p>Access modifiers are different, and typically aren't used with import <em>statements</em> in dynamic languages; public vs. private vs. package-private visibility is more a concept in static languages, which would have import <em>declarations</em> instead.</p>
<p>However, other dynamic languages such as Javascript do have a mechanism to control which module members are exported, via the <code>export</code> keyword. (Or in Python, this is controlled through the special <code>__all__</code> variable.) In this case, the implementation only needs to include just the module's exported members in the object, not all of its top-level names.</p>

CC BY-SA 4.0
2023-05-18T16:46:42.053Z
2023-05-19T04:23:17.097Z
2023-05-19T04:23:17.097Z
kaya3
CC BY-SA 4.0
2023-05-19T05:58:19.187Z
Are there examples of some languages that do not put imported modules into their own namespace automatically, except for something like C/C++?
FireTheLost
CC BY-SA 4.0
2023-05-19T06:27:46.140Z
@FireTheLost If you count "includes" as import statements, then sure ─ PHP is a notable example.
kaya3
# What are the different ways import statements can be implemented?
Posted by: username_0 on 2023-05-18
The only way that I know how `import` statements could be implemented is in the parsing stage where the imported module's `AST` is directly concatenated onto the main script's `AST` and the variables from the imported file are added to the main Symbol Table.

I wanted to know if this method is suitable for a production language, as it seems rather simplistic and does not take into account things like namespaces and access modifiers. Is there any advantage of doing it this way? Do any other languages just insert the AST into the main file?

If not, what other ways can this be implemented, regardless of import semantics, and how have other languages done it? What might the differences in implementation be in a dynamic language, like Python, vs a static language, like Rust?

If possible, could you please point to some links/implementations on GitHub?
**Tags:** implementation imports
> **Comments:**
> **username_1**: This assumes you're performing identifier resolution at compile time. If your languages defers scope until runtime (such as Python), then you don't add anything to the symbol table.  
> **username_2**: Possible duplicate of [What are the different ways of handling imports?](https://languagedesign.stackexchange.com/questions/313/what-are-the-different-ways-of-handling-imports)  
> **username_3**: @pppery That question is about the possible semantics of import declarations or statements; this question is about the implementation of import statements.  
> **username_3**: @user16217248 As I said, the other question is about possible semantics and this one is about implementation of one of those semantics. I don't see how it's unclear.  
> **username_4**: For the languages where imports are resolved at runtime, are you asking about the implementation of the runtime resolution? Or about attempts to do resolution statically for things like developer tooling? Or both?  
> **username_0**: More about the implementation of resolution  
---
## 2 answers
### Answer by username_3 on 2023-05-18. Score: 7 | Accepted answer
Here's how a modern dynamic language like Python might do it. Assume the interpreter maintains a cache of loaded modules, indexed either by the module name, filesystem path, or some other unique identifier.

If the module already exists in the cache, return the cached object.
Locate and open the appropriate source file for the imported module. If there is no such module, raise an error.
Insert an empty object for the module into the cache. (This marks the module's state as "in progress" and prevents unbounded recursion if there is a cyclic import.)
Recursively interpret the source file (i.e. invoke the interpreter's function for executing a source file).
Update the cache by adding the module's exported members to the object representing the imported module.
Bind the object or its imported members to the appropriate name(s) in the current scope.


The above might be difficult to follow, so here's an example. Suppose we have three files:
# foo.py
import bar
from baz import y
print(bar.x, y)

# bar.py
import baz
x = baz.y + 2

# baz.py
y = 3

We begin executing the program foo.py. Suppose Module is a class used to represent modules internally.

The first statement is import bar, so we locate and open bar.py, add bar: Module() to the cache, and begin executing the source in that file.

The first statement is import baz, so we locate and open baz.py, add baz: Module() to the cache, and begin executing the source in that file.

The statement y = 3 binds the name y to the value 3.


The property y: 3 is added to the module object associated with the name 'baz'.
The module object {y: 3} from the cache is bound to the name baz.
The statement x = baz.y accesses the y property from the module object baz, and binds the name x to the value 5.


The properties x: 5 and baz: {y: 3} are added to the module object associated with the name 'bar'.
The module object {x: 5, baz: {y: 3}} from the cache is bound to the name bar.
The second statement is from baz import y, and 'baz' is already in the cache, so we find the module object {y: 3} associated with it, and bind the name y to the value 3.
The final statement print(bar.x, y) reads the x property from the module object {x: 5, baz: {y: 3}}, and hence prints 5 3.



it seems rather simplistic and does not take into account things like namespaces and access modifiers

It does take into account namespaces ─ notice how a simple import statement like import bar binds the name bar to a module object which serves a namespace for bar's exported members. Moreover, since bar.py exports the baz module object, this could be accessed in foo.py as bar.baz.y.
Access modifiers are different, and typically aren't used with import statements in dynamic languages; public vs. private vs. package-private visibility is more a concept in static languages, which would have import declarations instead.
However, other dynamic languages such as Javascript do have a mechanism to control which module members are exported, via the export keyword. (Or in Python, this is controlled through the special __all__ variable.) In this case, the implementation only needs to include just the module's exported members in the object, not all of its top-level names.
> **Comments:**
> **username_0** (2023-05-19): Are there examples of some languages that do not put imported modules into their own namespace automatically, except for something like C/C++?  
> **username_3** (2023-05-19): @FireTheLost If you count "includes" as import statements, then sure ─ PHP is a notable example.  
---
### Answer by username_5 on 2023-05-18. Score: 3
# #include

Some languages, like C, C++, and Lua (partially), literally just copy-paste the imported file into the current file. This may have a propensity for making huge files and long compilation times, but it’s the simplest way that works.
> **Comments:**
> **username_6** (2023-05-23): Lua doesn't work this way exactly; the `require` function will only import the required script once. It will also return its return value, if any. [Reference.](https://www.lua.org/pil/8.1.html)  
---
