Skip to content

feat(data): require explicit () for singleton variants; deprecate bare form - #80

Merged
Roger-luo merged 5 commits into
mainfrom
feat/explicit-singleton-syntax
Jul 12, 2026
Merged

Roger-luo merged 5 commits into
mainfrom
feat/explicit-singleton-syntax

Conversation

@Roger-luo

@Roger-luo Roger-luo commented Jul 12, 2026 •

Copy link
Copy Markdown
Owner

Motivation

Follow-up to #22. The confusion in that issue comes from singleton variants being written as a bare identifier:

@data Score begin
    ZeroZero   # looks like a value...
    Plus(Int)
end

Score.ZeroZero is actually the variant type, not a value — you must call Score.ZeroZero() to get an instance of Score.Type. The bare syntax reinforces the wrong mental model, producing baffling convert/dispatch MethodErrors (see #22).

On "does Julia have singleton types?"

Yes — Julia has singleton types (an immutable no-field struct has exactly one instance; Base.issingletontype(Empty) == true, and Moshi's own Score.ZeroZero() === Score.ZeroZero() is true). But the type and its instance are always distinct objects (Nothing vs nothing); there is no way to make one bare name be simultaneously a type and its sole value the way a Rust enum variant is. Moshi needs the variant name to remain a type (for dispatch, reflection, and pattern matching), and a const value binding is impossible for generic ADTs (Option.None{Float64}). So the honest fix is to make the syntax explicit rather than fake a value binding.

Change

  • @data now accepts the explicit Name() singleton form (previously rejected with "missing fields") and treats it as the canonical spelling.
  • The bare Name form still parses to a Singleton but emits a Base.depwarn(...; force=true) at macro-expansion time pointing to Name().
  • Non-breaking (deprecation only). The version bump is left to release-please (release-type: julia); the feat: commit drives a patch bump automatically.
@data Score begin
    ZeroZero()   # ✅ canonical
    Plus(Int)
end

Scope

  • Core: src/data/cons.jl — accept Name(), deprecate bare Name.
  • Internal: src/match/repr.jl Wildcard → Wildcard() so Moshi doesn't warn on its own load; all test @data blocks migrated to ().
  • Docs: data/syntax.mdx, data/understand.mdx, start/* updated to teach Name() and explain the type-vs-value point + deprecation.
  • Tests: added coverage for the explicit form and the bare-form deprecation (guarded to skip under --depwarn=error, which escalates the warning to a throw).

Verification

  • Pkg.test() green: data 285 (+5 new), match 103, derive 30, perf 5.
  • Confirmed a real bare @data singleton warns at expansion, and the explicit Name() form constructs correctly with no warning.
  • JuliaFormatter (blue) reports all touched files unchanged.

Notes

Refs #22

🤖 Generated with Claude Code

…e form

Singleton variants were written as a bare identifier (`Quit`), which
reinforced the false expectation that `Score.ZeroZero` is a *value*. It
is not — it is the variant *type*; the value is `Score.ZeroZero()`. This
tripped up users (#22) with confusing `convert`/dispatch MethodErrors.

Julia has singleton *types* (an immutable no-field struct has one egal
instance, `Base.issingletontype` == true), but the type and its instance
are always distinct objects — there is no way to make a bare name be both
a type and its value the way a Rust enum variant is. Moshi needs the
variant name to stay a type (for dispatch/reflection/pattern matching),
so the honest fix is to make the *syntax* explicit rather than to fake a
value binding.

Changes:
- `@data` now accepts the explicit `Name()` singleton form (previously
  rejected with "missing fields") and treats it as the canonical spelling.
- The bare `Name` form still parses to a Singleton but emits a
  `Base.depwarn(...; force=true)` at macro-expansion time.
- Internal `Pattern` ADT (`Wildcard`) and all test/doc `@data` blocks
  migrated to the explicit `()` form so Moshi no longer uses its own
  deprecated syntax.
- Docs updated to teach `Name()` and explain the type-vs-value point.
- Added tests for the explicit form and the bare-form deprecation
  (guarded to skip under `--depwarn=error`, which escalates to a throw).

Non-breaking (deprecation only): bumps 0.3.9 -> 0.3.10.

Refs #22

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
moshi-jl Ready Ready Preview, Comment Jul 12, 2026 4:07pm

@github-actions

github-actions Bot commented Jul 12, 2026 •

Copy link
Copy Markdown
Contributor

Benchmark Results (Julia v1)

Time benchmarks
main 8b00e55... main / 8b00e55...
adt_transform/transform n=100 2.68 ± 0.21 μs 2.69 ± 0.17 μs 0.996 ± 0.1
adt_transform/transform n=1000 29.4 ± 0.78 μs 29.3 ± 0.84 μs 1 ± 0.039
linked_list/sum n=100 0.48 ± 0.01 μs 0.471 ± 0 μs 1.02 ± 0.021
linked_list/sum n=1000 5.16 ± 0.041 μs 5.11 ± 0.031 μs 1.01 ± 0.01
time_to_load 0.0831 ± 0.001 s 0.0819 ± 0.0016 s 1.01 ± 0.023
Memory benchmarks
main 8b00e55... main / 8b00e55...
adt_transform/transform n=100 0.178 k allocs: 5.94 kB 0.178 k allocs: 5.94 kB 1
adt_transform/transform n=1000 1.79 k allocs: 0.0583 MB 1.79 k allocs: 0.0583 MB 1
linked_list/sum n=100 0 allocs: 0 B 0 allocs: 0 B
linked_list/sum n=1000 0 allocs: 0 B 0 allocs: 0 B
time_to_load 0.145 k allocs: 11 kB 0.145 k allocs: 11 kB 1

This branch is based on main, which still points the benchmark page's
RawCode components at the old `../benchmark/*.jl` paths. PR #78 moved
those files into `../benchmark/comparison/`, so the docs build (and the
Vercel preview) crashes with `ENOENT: ../benchmark/expronicon.jl`.

Point all 7 paths at `../benchmark/comparison/`. `astro build` now
completes (22 pages, 0 errors). Same fix as #79; both converge to
identical content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The repo uses release-please (release-type: julia), which bumps
Project.toml + CHANGELOG.md from Conventional Commits on push to main.
Manually bumping to 0.3.10 conflicts with the manifest (still 0.3.9), so
revert to 0.3.9 and let the `feat:` commit drive the bump automatically.

Also de-hardcode the version in the singleton deprecation note, since the
exact release number is chosen by release-please.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Roger-luo and others added 2 commits July 12, 2026 12:06
…on-syntax

# Conflicts:
#	docs/src/content/docs/data/syntax.mdx
Records the lesson from this PR: manually bumping Project.toml in a
feature PR fights release-please and, once that version is released,
causes merge conflicts against main. Documents that release-please owns
Project.toml/CHANGELOG.md/manifest and derives the bump from commit types.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.42%. Comparing base (d3df3f8) to head (8b00e55).

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #80      +/-   ##
==========================================
+ Coverage   91.41%   91.42%   +0.01%     
==========================================
  Files          42       42              
  Lines        1607     1610       +3     
==========================================
+ Hits         1469     1472       +3     
  Misses        138      138              

☔ 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.

@Roger-luo
Roger-luo merged commit f79750c into main Jul 12, 2026
8 checks passed
@Roger-luo
Roger-luo deleted the feat/explicit-singleton-syntax branch July 12, 2026 16:31
github-actions Bot referenced this pull request Jul 12, 2026
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
Preview — 8b00e554 Deployed Jul 12, 2026 by vercel[bot]
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