# Modules and Imports
Deft's module system is file-path based. A module is a `.dft` file
loaded by path; declarations at the top level become the module's
public surface (with `def` introducing module-scoped bindings). The
`implements` declaration adds module-level conformance checks at
import time.
## `import` — Load a Module
`import "path" as alias` loads a module and binds its public surface
to a namespace alias:
import "deft/stdext/async" as async set results [async/await-all $futures]
Import paths take several forms:
- **Relative** — `"./helpers"` / `"../lib/util"` resolve against the
importing file's directory.
- **Package-qualified** — `"owner/name/sub/path"` (e.g.
`deft/ui/components/button`) resolves through the package mounts
auto-registered from the `:pkgs` roots. Append `@version` to the
name to pin (`deft/ui@0.1.0/...`); `@latest` is an explicit alias
for the unpinned resolution.
- **Mount-named** — any other leading segment that matches a prelude
`:mounts` entry or a `[pkg/mount ...]` registration. Longest mount
prefix wins, so qualified package names are never shadowed by a
single-segment mount.
- **CWD-relative** — a plain `"foo/bar"` whose file exists under the
working directory resolves locally before mounts are consulted.
Drop the `.dft` extension in the path. A failed package-qualified
import reports available versions (`no matching version; available:
...`); a bare package prefix suggests the qualified spelling
(`did you mean "deft/ui/..."?`).
### Resolving without importing
`[import/resolve "path"]` answers "which file would `import` load?"
without loading it — same resolver, same precedence (relative,
CWD-relative, mounts with version pins, stdext fallback):
[import/resolve "deft/ui/components/button"] # => ".deft/packages/deft/ui/0.1.0/src/components/button.dft" [import/resolve "deft/ui@0.1.0/components/button"] # explicit pin [import/resolve "./helpers"] # relative to caller
Returns the literal file path (with the `.dft` suffix loadFile would
use — `.../markdown.syntax` resolves to `.../markdown.syntax.dft`),
or nil when the import would not resolve. Useful for tooling:
jump-to-source, file watchers, dependency graphs, diagnostics.
Package **asset** paths resolve too — directories and package-root
files that `import` itself wouldn't load. A qualified reference
probes the subpath as a directory under the package's code dir, then
under the package root; a bare `"owner/name"` yields the package
root itself:
[import/resolve "deft/help/manual"] # → "packages/help/manual" (directory) [import/resolve "deft/help/help.md"] # → "packages/help/help.md" (root file) [import/resolve "deft/help"] # → "packages/help" (package root)
So apps that need a package's data directory (doc trees, themes,
assets) can derive it from the same `owner/name` identity the code
imports use — no hand-rolled path probing per install layout.
### `from ... import`
`from "path" import @{ name1 name2 }` pulls individual names into the
current scope without an alias:
from "deft/stdext/async" import @{ await-all map-concurrently } set xs [await-all $futures]
The names list is a Deft list literal — `@{...}` for many names,
single symbols also work.
## Namespaces
Every runtime has a `current-ns` — the namespace into which top-level
`def`s go. The default namespace is `"user"`.
[current-ns] # => "user" [in-ns "my-app"] # switch namespace
`in-ns` is rarely used in scripts; it's primarily for REPL sessions
and runtime/tooling code that manages namespaces dynamically.
### Module namespace
When you `import "foo/bar" as bar`, the loaded module's namespace
becomes accessible as `bar/name`:
# In stdext/async.dft: def await-all {|futures| ... } # In your script: import "deft/stdext/async" as async [async/await-all $futures] # ← name resolved through alias
## `implements` — Module Conformance
A module may declare that it conforms to an interface. At import
time, Deft verifies that all functions required by the interface are
exported:
# my-app/storage.dft implements StorageInterface def get {|key| ... } def put {|key val| ... } def delete {|key| ... }
If a required function is missing, the import fails with an error
naming the missing function, and the script never reaches code after
the failed import:
```
module my-app/storage impls StorageInterface but missing export: delete
```
A module without an `implements` declaration has no conformance
requirements. A conforming module may export additional functions
beyond what the interface requires.
> `implements` is a **module-level** conformance check (does this
> file export the required names?). It's distinct from
> `defprotocol`/`defimpl`, which are **type-level** protocols
> governing method dispatch on values. See [Types and
> Protocols](types-and-protocols).
## Defining an Interface
An interface is a module that declares a list of required exports.
The simplest form is a module that documents the expected names;
Deft's checker walks the imports and looks them up.
# stdext/storage_iface.dft # # Modules implementing StorageInterface must export: get, put, delete. def required-names ^{:get :put :delete}
A real interface module typically also defines the types or
documentation that implementers need. See `test/test_impls.dft` for
the canonical example.
## Packages
A **package** is a directory of Deft modules with a `package.dft`
manifest. Packages are the unit of distribution: install via
`pkg/install`, mount into a runtime, and import from any module.
def manifest %Package{ :owner "alice" :name "math-lib" :version "1.0.0" :description "Personal math helpers" }
See [Packages](../07-Tooling/packages) for the package manifest
format, `pkg/*` stdlib functions, and `.dfs` distribution files.
## Search Paths
Unqualified paths resolve in this order:
1. CWD-relative (`/foo/bar.dft` or its directory-index form),
only when the file exists.
2. Mount names (longest prefix first): package-qualified
`owner/name[@version]` mounts from the `:pkgs` auto-scan, then
single-segment prelude `[pkg/mount]` mounts.
3. The stdext subpath fallback for `syntax/*` modules.
See [Packages](../07-Tooling/packages) for the `:pkgs` roots and
package reference syntax.
## Circular Imports
Deft does not support circular imports. If module A imports B and B
imports A, the loader detects the cycle and raises an error at load
time. Refactor to break the cycle, or use `pub/*` to communicate
between the modules at runtime.
## Reload
`[reload "path"]` reloads a module that has changed on disk. Useful
during development (especially in the REPL or a long-running TUI app).
Existing references to old definitions are not updated; only future
lookups resolve to the new version.
[reload "my-app/foo"]
## Information About Loaded Modules
The `info/*` namespace exposes the module table:
[info/modules] # list of loaded module names [info/defs] # defs in the current namespace [info/vars] # vars in the current namespace [info/resolve "name"] # resolve a name to its source
See [Metaprogramming](metaprogramming) for the full `info/*` API.
## Quick Reference
| Form | Purpose |
|---|---|
| `import "path" as alias` | Load module, bind to alias |
| `from "path" import @{ names }` | Pull in specific names |
| `[in-ns "name"]` | Switch current namespace |
| `[current-ns]` | Get current namespace name |
| `implements InterfaceName` | Declare module conformance (checked at load) |
| `[info/modules]` | List loaded modules |
| `[reload "path"]` | Reload a module |