Summary
I would like to start a discussion on an idea for enhancing Scala’s import resolution model by introducing a physical import syntax inspired by concepts like ECMAScript “import maps” and Go module paths. This design would coexist with existing package imports and aim to improve inspectability and learnability for both LLM-based tooling and developers without IDE support.
Motivation
Existing JVM import semantics (import org.apache.xxx…) rely on classpath and binary artifacts, which creates two usability issues:
-
Tooling blind spots — Without sophisticated IDE integration, it is hard to inspect the definition or signature of a class from its name alone. This is a known pain point for developers, especially newcomers, who lack immediate visibility into API contract and implementation details.
-
LLM assistance ambiguity — Because import names do not directly map to local source or semantic artifacts, large language models may produce outdated, inferred, or incorrect signatures when assisting with code completion or generation.
These issues are structural, not merely tooling gaps — they stem from a language resolution model that is semantic and binary oriented rather than physically inspectable.
Proposal: Physical Import Syntax + Import Map
Introduce a string-literal import syntax that is resolved via a project-level import map:
import "spark/sql/Dataset"
In this model:
-
The quoted string is a physical import path, akin to how ECMAScript import maps allow bare specifiers to be mapped to URLs or file paths. You can see the import-map concept here: Import Maps specification and usage examples. (developer.mozilla.org)
-
A workspace-level import map defines the binding of logical roots to specific artifacts:
{
"imports": {
"spark": "com.apache.spark:spark-core_3:3.5.1",
"flink": "org.apache.flink:flink-core:1.19.0"
}
}
This import map functions like the browser import maps idea for JS modules, where a bare specifier resolves to a defined module path. (developer.mozilla.org)
- During compilation, the string import resolves through the import map to a local materialized directory (e.g., extracted
.tasty, source, or semantic representation) — enabling deterministic lookup.
This combination preserves compatibility with the normal Scala import syntax while giving an inspectable resolution path.
Analogies and Precedents
-
ECMAScript Import Maps — Let developers map symbolic specifiers to concrete paths before module resolution. (developer.mozilla.org)
-
Go module paths — Although Go imports are full module paths (e.g.,
"``github.com/foo/bar/v2``"), they are explicit strings tying import to a known on-disk identity. What’s proposed here decouples the resolution from opaque classpath mechanisms and makes it local and inspectable. (Go)
Both show that explicit, resolvable import mappings improve tool predictability.
Benefits Beyond LLMs
This design is not only LLM-friendly — it also benefits human developers, especially new Scala programmers:
-
Improved learnability — With conventional imports, a developer without an IDE must search external repositories or rely on external indices to locate definitions. Physical imports make it trivial to navigate to definitions.
-
Better tooling support — Tools (linters, static analyzers, docs generators, refactoring tools) can deterministically follow import references.
-
Explicit version binding — Import maps make dependency versioning explicit and centralized, reducing ambiguity about which artifact version a symbol refers to.
This aligns with broader community goals around learnability and tooling; for example, recent discussions about ecosystem learnability indicate the need for improvements in tooling and discoverability. (Scala)
Example Workspace
workspace/
├── module-a/
│ ├── lib/
│ │ ├── spark/ (resolved via import map)
│ │ │ └── sql/
│ │ │ ├── Dataset.tasty
│ │ │ └── Encoder.tasty
│ ├── src/
│ └── test/
└── module-b/
With an import map I can write:
import "spark/sql/Dataset"
and tooling can directly navigate to the physical path in module-a/lib/spark/sql.
Discussion Questions
-
Design suitability: Would contributors be receptive to exploring physical import paths as a language extension separate from dotted package imports?
-
Integration with build tools: How might this interact with sbt, Coursier, and other Scala/JVM build ecosystems?
-
Import map format: What are desirable semantics and formats for an import map in a Scala context?
-
Compiler/toolchain considerations: What are possible implementation challenges (e.g., incremental compilation, TASTy extraction, cross-module resolution)?
-
Community precedent: Are there related past discussions in the Scala community on import resolution, tooling transparency, or semantic extraction?
Next Steps
I am seeking initial feedback on this idea so that — if there is community interest — we can refine a pre-SIP proposal with clearer grammar, resolution semantics, and prototyping plans.
References
-
Import maps allow bare module specifiers to be mapped to concrete paths for JavaScript modules: script type=“importmap” specification. (developer.mozilla.org)
-
Go modules use explicit module paths defined in
go.mod, which become import paths in code. (Go) -
Tooling and learnability continue to be areas of focus for Scala ecosystem improvement. (Scala)