Appendix to Connectivities as types. The mechanics behind rules 1 and 3-6 of Identity is the qualified Python name: reconstruction by import, the one copyreg hook, fingerprinting, the injective codegen mangling, and the Staggered[D] tag grammar.

Rule 1 — reconstruction from the IR is an import

  1. Reconstruction from the IR is an import. resolve(tag) imports the longest importable module prefix and walks the rest as attributes (nested classes like V2E.Local resolve naturally), the way pickle references a class. Only where the module path ends is memoized: the attribute walk is repeated, so a declaration redefined under the same name (a re-run notebook cell) resolves to the new class. AxisLiteral stores only the tag and derives kind and dim from it as read-only properties (the TODO at iterator/ir.py:93); the derived kind is optional, since a local dimension’s is None; printing IR never imports (resolve_loaded). Staggered[D] tags use the small grammar <owner tag>[<base tag>], resolved by subscripting the owner.

Rules 3-6 — registry, fingerprints, mangling, staggering

  1. No registry. Classes pickle by reference. One narrow copyreg hook exists, for Staggered[D], whose bracketed qualname save_global cannot look up; it reduces to the base dimension and re-interns.
  2. Fingerprints depend on qualified names, plus kind. A dimension is deconstructed as its by-reference name and its declaration-time kind, which decides a field’s layout order and the scan axis — so a dimension redefined under the same name with another kind does not reuse artifacts. Staggered[D] goes through its base and inherits this; its base cannot be flipped in place, since the class is interned by base identity and its tag embeds the base tag. The axis level (CartesianAxisIndex versus DimensionIndex) is deliberately not fingerprinted: it changes what is accepted, never what is emitted. A connectivity declaration is fingerprinted additionally by its domain, codomain, Local and counts. Consequently the ADR 0023 build cache invalidates on module renames.
  3. Codegen names need injective mangling. codegen_name(tag) is a prefix escape — _→_u, .→_d, [→_l, ]→_r — used by gtfn, DaCe, the roundtrip backend and the nanobind bindings; its inverse from_codegen_name is used by DaCe to parse names back. The simpler “escape __, then replace .” is not injective (".." and "_" collide); the prefix escape is tested exhaustively over its alphabet up to length 4.
  4. Staggering is part of the dimension change. The _Staggered name prefix needs the name→class lookup that type identity removes, so Staggered[D] is a real class and part of ADR 0029 (PR A), together with the Cartesian axis dimensions its parameter is bounded on; see [[personal/egparedes/connectivities-as-types/connectivities-as-types#staggeredd|Staggered[D]]].

The Staggered[D] tag

  • IR and serialization. The tag is gt4py.next.common.Staggered[<base tag>] — the one tag that is not a qualified name. resolve parses the <owner>[<base>] grammar and subscripts the owner, the IR pretty-parser accepts it, and codegen_name escapes the brackets. pickle cannot look up a bracketed qualname, so one copyreg hook reduces a staggered class to its base and re-subscripts on load; fingerprints are likewise taken through the base.