Skip to content

Commit 2c1ee5c

Browse files
ChrisRackauckas-ClaudeChrisRackauckasclaude
authored
Add AGENTS.md with code generation conventions (#5105)
Records three conventions that came up in review of #5045: no `gensym` in names that reach generated code (it defeats the RuntimeGeneratedFunctions Expr-hash cache), build `Expr`s by pushing onto `args` instead of splatting, and keep codegen-side containers concretely typed vectors rather than tuples. Agent-Harness: Claude Code 2.0.14 Agent-Model: claude-opus-5[1m] Agent-Session: https://claude.ai/code/session_01GdSpCLd7NBZuuePJmcDzU7 Claude-Session: https://claude.ai/code/session_01GdSpCLd7NBZuuePJmcDzU7 Co-authored-by: ChrisRackauckas-Claude <accounts@chrisrackauckas.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 88d9ad9 commit 2c1ee5c

1 file changed

Lines changed: 46 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# AGENTS.md
2+
3+
Repository-specific conventions for ModelingToolkit.jl. See `CONTRIBUTING.md` for the
4+
style and formatting rules that apply to every SciML repository.
5+
6+
## Code generation
7+
8+
### Never `gensym` a name that ends up in generated code
9+
10+
Names embedded in an `Expr` that is handed to `eval_or_rgf` / `RuntimeGeneratedFunction`
11+
must be fixed symbols, not `gensym`s. A `gensym` embeds a process-global counter, so the
12+
same system lowers to a different `Expr` in the precompile process than in the user
13+
session. That defeats the `RuntimeGeneratedFunctions` Expr-hash cache: precompiled bodies
14+
are never hit, every `Expr` is a distinct type, and constructing the same problem twice
15+
recompiles the generated function.
16+
17+
Use a fixed sentinel instead, prefixed `__mtk_` (see `generated_argument_name`) or
18+
suffixed `ₘₜₖ` (see `HOMOTOPY_LAMBDA`, `__log_assertions_ₘₜₖ`). Both make a collision with
19+
a user-chosen symbol implausible; where a collision would silently produce wrong code
20+
rather than an error, guard against it explicitly as `lower_homotopy` does.
21+
22+
`gensym` remains fine for names that never reach generated code, such as the default
23+
`name` of a system built by `modelingtoolkitize`.
24+
25+
### Build `Expr`s by pushing, not splatting
26+
27+
Prefer `push!`/`append!` onto `expr.args` over `Expr(head, xs...)`. The splat is a
28+
dynamic call whose argument count is unknown to the compiler, so it inflates codegen time
29+
and infers poorly:
30+
31+
```julia
32+
# no
33+
Expr(:tuple, buffers...)
34+
35+
# yes
36+
tup = Expr(:tuple)
37+
append!(tup.args, buffers)
38+
```
39+
40+
### Keep codegen-side containers concretely typed vectors
41+
42+
Collections that codegen iterates over — parameter groups, buffer lists, argument lists —
43+
should be a concretely typed `Vector`, not a tuple of tuples. Tuples force the whole
44+
surrounding loop to specialize on the shape of each individual system, which is
45+
catastrophic for inference and compile time. Reserve tuples for values that genuinely
46+
need to be heterogeneous or statically sized in the *generated* code.

0 commit comments

Comments
 (0)