Import Basics#
Jac provides a powerful and flexible import system to organize code across multiple files and packages.
Prefer Absolute Imports
We recommend using absolute imports over relative imports. Absolute imports are explicit, easier to read, and avoid ambiguity.
Import Syntax Overview#
| Pattern | Syntax | Use Case |
|---|---|---|
| Absolute import | import module; |
Import entire module |
| From-import | import from module { X, Y } |
Import specific symbols |
| Include (wildcard) | include module; |
Include all symbols into namespace |
| Aliased import | import module as alias; |
Rename module |
| From-import alias | import from module { X as Y } |
Rename symbol |
File Extensions
Jac resolves both .jac and .py files, you don't need to include the extension in import paths. This makes Jac fully interoperable with Python modules.
Absolute Import#
Import an entire module and access its members using dot notation.
import module_a;
with entry {
print(f"Absolute import - VALUE_A: {module_a.VALUE_A}");
print(f"Absolute import - greet(): {module_a.greet()}");
}
glob VALUE_A = "Hello from module_a";
def greet -> str {
return "Greet from module_a";
}
Output
```
Absolute import - VALUE_A: Hello from module_a Absolute import - greet(): Greet from module_a ```
When to use
Use absolute imports when you need multiple items from a module and want to make the source clear (e.g., module_a.VALUE_A).
From-Import (Selective Import)#
Import specific symbols directly into your namespace.
import from module_b { VALUE_B, calculate, MyClass }
with entry {
print(f"From-import - VALUE_B: {VALUE_B}");
print(f"From-import - calculate(5): {calculate(5)}");
obj_instance = MyClass();
print(f"From-import - MyClass: {obj_instance.name}");
}
glob VALUE_B = "Hello from module_b";
glob ANOTHER_VALUE = 100;
def calculate(x: int) -> int {
return x * 2;
}
obj MyClass {
has name: str = "MyClass instance";
}
Output
```
From-import - VALUE_B: Hello from module_b From-import - calculate(5): 10 From-import - MyClass: MyClass instance ```
When to use
Use from-imports when you need specific items and want shorter names in your code.
Include Statement (Wildcard Import)#
The include statement imports all public symbols from a module directly into your namespace.
include module_c;
with entry {
print(f"Star import - PUBLIC_VAR: {PUBLIC_VAR}");
print(f"Star import - public_func(): {public_func()}");
}
glob PUBLIC_VAR = "I am public";
glob _PRIVATE_VAR = "I am private";
def public_func -> str {
return "Public function";
}
def _private_func -> str {
return "Private function";
}
Output
```
Star import - PUBLIC_VAR: I am public Star import - public_func(): Public function ```
Private symbols
Symbols starting with _ (underscore) are considered private and are not included.
Use sparingly
Include statements can pollute your namespace. Prefer explicit imports in production code.
Aliased Imports#
Rename modules or symbols during import to avoid conflicts or for convenience.
import module_d as md;
import from module_d { long_function_name as lfn }
with entry {
print(f"Import as - md.LONG_MODULE_VALUE: {md.LONG_MODULE_VALUE}");
print(f"From import as - lfn(): {lfn()}");
}
glob LONG_MODULE_VALUE = "Value from long named module";
def long_function_name -> str {
return "Result from long function";
}
Output
```
Import as - md.LONG_MODULE_VALUE: Value from long named module From import as - lfn(): Result from long function ```
When to use
- Shorten long module names
- Avoid naming conflicts
- Create more descriptive names
Key Takeaways#
| Concept | Description |
|---|---|
import X; |
Access via X.symbol |
import from X { Y } |
Access Y directly |
include X; |
All public symbols available directly |
import X as Z; |
Access via Z.symbol |
import from X { Y as Z } |
Access Y as Z |
Best Practice: Use Absolute Imports
Absolute imports like import from mypackage.module { X } are clearer and more maintainable than relative imports.