Skip to content

Add the of type from JuliaBUGS.jl#168

Open
sunxd3 wants to merge 8 commits into
mainfrom
sunxd/of-type-migration
Open

Add the of type from JuliaBUGS.jl#168
sunxd3 wants to merge 8 commits into
mainfrom
sunxd/of-type-migration

Conversation

@sunxd3

@sunxd3 sunxd3 commented Jun 1, 2026

Copy link
Copy Markdown
Member

Adds the of type system to AbstractPPL: a small, declarative way to describe the shape, element type, and support of model parameters as ordinary Julia types.

of(...) and the @of macro construct OfType specifications that double as type annotations. Only of and @of are exported; flatten/unflatten and the OfType subtypes are marked public.

Highlights:

  • Scalar, bounded, array, and named-tuple specs: of(Float64, 0, 1), of(Int), of(Array, 3, 4), @of(mu = of(Real), sigma = of(Real, 0, nothing)), and constants via constant=true.
  • Symbolic dimensions and bounds — including arithmetic such as n + 1 — resolved with of(T; n=...).
  • rand, zero, size, length, and flatten/unflatten over the specs; unflatten is AD-transparent and type-stable.

The implementation is moved and then updated from JuliaBUGS.jl.

Move the self-contained `of` type-specification system into AbstractPPL so
downstream packages can share a common vocabulary for the shape, element type,
and support of model variables (previously in JuliaBUGS/src/of_type.jl).

- src/of.jl: the `of`/`@of` system minus the JuliaBUGS-specific
  `of(::BUGSModel)` method; only external dependency is Random.randexp.
- Export `of` and `@of`; mark the `Of*` types and flatten/unflatten/
  inspection helpers `public` (guarded for the 1.10 compat floor).
- Add test/of.jl (wired into the Tests group) and docs/src/of.md.
- Bump to 0.15.3 with a HISTORY entry.
@codecov

codecov Bot commented Jun 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.66420% with 60 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.51%. Comparing base (123cdd4) to head (69266ff).

Files with missing lines Patch % Lines
src/of.jl 93.66% 60 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #168      +/-   ##
==========================================
+ Coverage   89.48%   91.51%   +2.02%     
==========================================
  Files          16       17       +1     
  Lines        1056     2003     +947     
==========================================
+ Hits          945     1833     +888     
- Misses        111      170      +59     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

AbstractPPL.jl documentation for PR #168 is available at:
https://TuringLang.github.io/AbstractPPL.jl/previews/PR168/

sunxd3 and others added 6 commits June 5, 2026 15:30
Follow-up review fixes for the JuliaBUGS `of` migration:

- @Of arithmetic dimensions now emit a hygienic `GlobalRef` to `SymbolicExpr`,
  so they resolve under a plain `using AbstractPPL` (previously threw
  UndefVarError for any downstream user; masked by the test importing it).
- `show` methods guard against non-concrete `of`-types (free TypeVars) and fall
  back to Base's Type printer, instead of throwing UndefVarError mid-backtrace
  when rendering method signatures / stacktraces / `methods()` / Documenter.
- `flatten`/`unflatten` are now type-stable (`@generated`) and AD-transparent:
  `flatten` returns a concrete promoted element type (pure-Int stays
  `Vector{Int}`), and `unflatten` preserves wide/AD eltypes via
  `promote_type(declared, eltype(flat))`, so `ForwardDiff.Dual` / `BigFloat`
  flow through array fields (previously coerced to the declared Float type).
- Add `rand(::AbstractRNG, ::Type{<:OfType})` methods for reproducible draws.
- `has_symbolic_dims`/`get_unresolved_symbols` now detect symbolic *bounds*, so
  `zero`/`rand`/`flatten` fail with a clear message instead of a raw MethodError.
- Reject top-level `OfConstantWrapper` in flatten/unflatten instead of silently
  returning `nothing`; narrow the instance constructor to `OfNamedTuple`; guard
  symbolic division on the result; `validate_bounds` takes a keyword `kind=`;
  fix the 0-dim array `show` trailing comma and the `length` docstring.
- Remove the broken `dims.rows` nested-reference docstring example; rewrite the
  rand/flatten/unflatten docstrings; drop redundant restate-the-code comments.

Add regression tests covering all of the above (including a `using`-only
submodule, non-concrete `show`, an AD/eltype round-trip, `@inferred` coverage,
and RNG reproducibility), and revive two stale/broken `@test_skip`s.
Remove redundant/obvious comments and all JuliaBUGS migration framing from
of.jl, test/of.jl, docs/src/of.md, and HISTORY.md so comments describe the
code as it is now. Drop a few trailing comments that merely restated the
adjacent code, and add a short note on the `eval(Meta.parse("public ..."))`
pre-1.11 workaround.

Trim the `public` declaration for the `of` type system to the genuinely
user-facing names (the `OfType` subtypes plus `flatten`/`unflatten`). The
internal type-parameter extractors (`get_*`, `is_leaf`, `get_wrapped_type`,
`get_unresolved_symbols`) and the `validate_bounds` helper are no longer
marked public; they remain reachable by qualification.
Convert the code blocks on the `of` documentation page to `@example` blocks
so they run during `makedocs` (Documenter 1.17): the long symbolic-dimension
and arithmetic examples are split into small rendered steps, `rand` uses a
seeded RNG for reproducible output, and the intentional-error cases are caught
with `showerror`. Add `Base.rand`/`zero`/`size`/`length` to the API-reference
`@docs` block so the docstrings' cross-references resolve, and `using Random`
to make.jl for the `rand` signature entry.

Attach the `rand` docstring to the bare `Base.rand(::AbstractRNG, ::Type{<:OfType})`
signature (mirroring abstractprobprog.jl) so the signature-qualified `@docs`
entry resolves; no method or behavior change.
Raises src/of.jl line coverage from ~77% to ~97% by exercising the
previously-untested branches: the non-instantiable leaf constructors,
`eval_symbolic_expr` operations and error paths, the single-sided and
unbounded `rand`/`zero` branches, value-validation failures, default-value
and `missing` initialisation, symbol collection across symbolic dimensions
and bounds, bound resolution under concretization, `unflatten(T, missing)`,
expression formatting, and the colored/symbolic `show` methods including the
constant-wrapper fallbacks.
Comment thread src/AbstractPPL.jl
Comment on lines +99 to +108
export of, @of
@static if VERSION >= v"1.11.0"
eval(
Meta.parse(
"public OfType, OfReal, OfInt, OfArray, OfNamedTuple, OfConstantWrapper, " *
"flatten, unflatten",
),
)
end

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new public keywords worth reviewing

…fixes

Incorporates review of the Codex changes:

- Validate user input: array dimensions must be nonnegative integers or
  symbolic, bound specs must have lower <= upper, and array element types
  must be `<: Number` (allows Real and Complex; rejects non-numeric types
  that would crash zero/rand/flatten).
- Partial concretization of arithmetic dimensions via `substitute_symbolic_expr`
  (resolve some symbols, keep the rest as a `SymbolicExpr`).
- Resolve symbolic bounds when concretizing bare `OfReal`/`OfInt` and unwrap
  `OfConstantWrapper`; validate and normalise constant values; drop nested
  all-constant blocks instead of erroring.
- Restrict `@of` symbolic references to earlier `constant=true` fields and
  fail fast on unsupported expressions; make `@of` resolve `of` via GlobalRef
  so it is unaffected by caller scope.
- Fix 0-dimensional arrays (pass `dims` rather than splatting), use
  `sprint(showerror, e)` for validation messages, and reject unknown/extra
  fields.
- Docs: describe `of` results as schema types for downstream annotation
  systems (an `of` type is not a supertype of values).

Keeps the `public` surface minimal (the `OfType` subtypes plus flatten/unflatten).
@sunxd3

sunxd3 commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

@yebai @shravanngoswamii this is ready if you have time to do a review pass. Otherwise I'll merge it the day after tomorrow, given that the risk is low.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant