Skip to content

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.

absolute_import/

absolute_import/main.jac
import module_a;

with entry {
    print(f"Absolute import - VALUE_A: {module_a.VALUE_A}");
    print(f"Absolute import - greet(): {module_a.greet()}");
}
View on GitHub

absolute_import/module_a.jac
glob VALUE_A = "Hello from module_a";

def greet -> str {
    return "Greet from module_a";
}
View on GitHub
absolute_import/
├── main.jac
└── module_a.jac
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.

from_import/

from_import/main.jac
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}");
}
View on GitHub

from_import/module_b.jac
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";
}
View on GitHub
from_import/
├── main.jac
└── module_b.jac
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_statement/

include_statement/main.jac
include module_c;

with entry {
    print(f"Star import - PUBLIC_VAR: {PUBLIC_VAR}");
    print(f"Star import - public_func(): {public_func()}");
}
View on GitHub

include_statement/module_c.jac
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";
}
View on GitHub
include_statement/
├── main.jac
└── module_c.jac
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.

aliased_import/

aliased_import/main.jac
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()}");
}
View on GitHub

aliased_import/module_d.jac
glob LONG_MODULE_VALUE = "Value from long named module";

def long_function_name -> str {
    return "Result from long function";
}
View on GitHub
aliased_import/
├── main.jac
└── module_d.jac
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.