control-toolbox / control-toolbox/OptimalControl.jl
Enforce Handbook tenet 2: `using`, never `import`
- Dominant language
- Julia
- Stars
- 135
- Forks
- 11
- Avg merge
- 6h 54m
- Merged PRs (30d)
- 56
Description
## Context
The control-toolbox Handbook mandates, in tenet 2 of [`PHILOSOPHY.md`](https://github.com/control-toolbox/Handbook/blob/main/PHILOSOPHY.md) (detailed in [`philosophy/modules.md#using-never-import`](https://github.com/control-toolbox/Handbook/blob/main/philosophy/modules.md#using-never-import)):
> Everything is qualified — with `using`, never `import`. Bring modules into scope, not their symbols (`using Pkg: Pkg`, `using Pkg: Sub`); call `Module.symbol` everywhere and extend methods qualified (`Base.show(...)`).
Two distinct violations to fix here:
1. `import` anywhere — replace with `using`.
2. The dotted submodule form `using Pkg.Sub` — it silently pulls `Sub`'s **exported** names into scope too (unlike `using Pkg: Sub`), which the Handbook explicitly forbids.
Translation table (from `philosophy/modules.md`):
| Instead of | Write |
|---|---|
| `import Pkg` | `using Pkg: Pkg` |
| `import Pkg.Sub` | `using Pkg: Sub` |
| `import Pkg.Sub: Sub` | `using Pkg: Sub` |
| `import Pkg: sym1, sym2` | `using Pkg: sym1, sym2` |
| `using Pkg.Sub` (forbidden) | `using Pkg: Sub` |
## Scope — doc, code, and tests
- **Code** — `src/`, `ext/`, and any `# Example` docstring blocks.
- **Docs** — `docs/src/*.md` (`@example`/`@setup` blocks) and any other `.md` showing Julia code (README, `BREAKING.md`/`CHANGELOG.md` migration snippets).
- **Tests** — everything under `test/`, plus a regression-guard test (see below) so this can't silently regress again.
⚠️ Exception: a migration doc that quotes a **past** API verbatim in a "Before" snippet should be left as-is — that's a historical fact, not a style violation. Only fix "After"/current-usage examples.
## Finding offending lines
```bash
# `import` statements, anywhere in Julia code or Markdown docs
rg --fixed-strings 'import ' -g '*.jl' -g '*.md' .
# forbidden dotted `using Pkg.Sub` form
rg -n 'using [A-Za-z][A-Za-z0-9]*\.[A-Za-z]' -g '*.jl' -g '*.md' .
```
Current count in this repo (rough — includes some CHANGELOG/BREAKING prose mentions that don't need changing; review each hit):
- `import`: **~87**
- dotted `using Pkg.Sub`: **~3**
## Regression guard
CTLie already completed this migration ([control-toolbox/CTLie.jl#24](https://github.com/control-toolbox/CTLie.jl/pull/24)) and added a meta-test that scans every tracked `.jl`/`.md` file for both patterns:
[`test/suite/meta/test_no_import.jl`](https://github.com/control-toolbox/CTLie.jl/blob/4f50e649ab067373834f8db7f52f3bbb5c19fd1f/test/suite/meta/test_no_import.jl)
It's self-contained and auto-discovered by the standard `CTBase.run_tests` runner (`suite/*/test_*` glob) — copy/adapt it directly, and extend the `DOTTED_USING_EXEMPT` list for any files here with legitimate historical "Before" snippets.
## Note on sibling submodule imports
If this repo has a submodule manifest structure (`src//.jl`), relative sibling imports like `using ..Lower` or `using ..Core: AbstractTag` are fine as-is and **not** part of this rule. Only the **absolute dotted** form (`using Pkg.Sub`, with a real package name, not `..`) is forbidden.
---
🤖 Filed with [Claude Code](https://claude.com/claude-code)
Contributor guide
Assessment
This issue has not been assessed yet.