Skip to content

Make a quantity default compile, and take the two SonarCloud findings - #190

Merged
matt-edmondson merged 2 commits into
mainfrom
claude/blissful-euler-fzuap2
Sep 14, 2026
Merged

matt-edmondson merged 2 commits into
mainfrom
claude/blissful-euler-fzuap2

Conversation

@matt-edmondson

@matt-edmondson matt-edmondson commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Two commits following #189. The first is cleanup; the second is a bug in what #189 shipped, found while preparing Holotype to consume it.

A quantity default did not compile

#189's QuantityCppTests compiled a promising class of quantities, but none of them had a default. Holotype's rigid_body.schema.json does — Mass starts at 1.0, Restitution at 0.5, Radius at 0.5 — and that is where it falls over.

A generated C++ quantity refuses a bare number twice over. Its own constructor is explicit — "a bare value never becomes a Mass by accident" — and so is the constructor of the Quantity that constructor takes:

class Mass {
    using underlying = Quantity<Dimension<0, 1>>;
    explicit constexpr Mass(underlying value) noexcept;   // one
};
// and in quantity.hpp
explicit constexpr Quantity(Rep value) noexcept;          // two

So holo::Mass{ 1.0f } is not one conversion the compiler will make but two, and the header the generator wrote did not compile against the vocabulary it had just been told to name. What compiles is the step said out loud:

holo::Mass mass = holo::Mass{ holo::Mass::underlying{ 1.0f } };

A vector form spells the same alias component and takes one per component, so a single default starts every component there — the same reading a numeric default on a built-in vector already gets.

A second thing was wrong on the same line: CppFileBuilder.Represented did not follow a quantity to its storage, so a float-stored quantity got 1 rather than 1.0f — an int literal a braced initialiser refuses for narrowing, which is the whole reason to brace it.

The alias names are ktsu.Semantics.Cpp's, which is a coupling rather than a deduction: CppGeneratorOptions.Quantities is the target saying its vocabulary came from there. So it is compiled rather than assumed. The stub vocabularies in both test files are now explicit in both places instead of being aggregates that would have accepted either spelling — so the new test fails if the generator goes back to the single brace — and TheModernisedSampleCompiles exercises it on a real sample, whose gravity has a default of -9.81.

The two SonarCloud findings

The gate passed on #189 but reported two new issues, and it merged before the fix landed. Both are on code #189 added.

S3358 (major) — CppReflectionBuilder.Measured had a nested ternary. The first branch is a guard rather than an alternative: a quantity knows its own dimension, so nothing else needs asking. Written as one, the remaining ternary is the honest either/or between a unit that resolves and one that does not.

S3218 (critical) — QuantityInfo.Components is the property a caller reads, and a private Components(Type) on the enclosing QuantityRegistry shadowed it from inside the record. The helper is now ComponentsOf, which also puts it alongside DimensionOf: both are named for the question rather than the answer.

Tests

775 → 779, all passing. QuantityCppTests gains ADefaultIsConstructedTheWayTheVocabularyAcceptsIt, which checks the nesting and then compiles it under -std=c++20 -Wall -Wextra.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UGHDsYaaTQdzVR4XBR6miu

S3358: Measured had a nested ternary. The first branch is a guard - a
quantity knows its own dimension and nothing else needs asking - so it
reads as one.

S3218: QuantityInfo.Components is the property a caller reads, and a
private Components(Type) on the enclosing class shadowed it from inside
the record. The helper is now ComponentsOf, which also matches
DimensionOf beside it: both are named for the question rather than the
answer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGHDsYaaTQdzVR4XBR6miu
A generated C++ quantity refuses a bare number twice over. Its own
constructor is explicit - a bare value never becomes a Mass by accident -
and so is the constructor of the Quantity that constructor takes. So
`holo::Mass{ 1.0f }` is not one conversion the compiler will make but
two, and the header the generator wrote did not compile against the
vocabulary it named.

What compiles is the step said out loud:
`holo::Mass{ holo::Mass::underlying{ 1.0f } }`. A vector form spells the
same alias `component` and takes one per component, so a single default
starts every component there - the same reading a numeric default on a
built-in vector already gets.

Two smaller things were wrong with the same line. CppFileBuilder's
Represented did not follow a quantity to its storage, so a float-stored
quantity got `1` rather than `1.0f` - an int literal a braced initialiser
refuses for narrowing, which is the whole reason to brace it.

Both alias names are ktsu.Semantics.Cpp's, which is a coupling rather
than a deduction: CppGeneratorOptions.Quantities is the target saying its
vocabulary came from there. So it is compiled rather than assumed. The
stub vocabularies in both test files are now explicit in both places
instead of being aggregates that would have accepted either spelling, and
TheModernisedSampleCompiles exercises it on a real sample, whose gravity
has a default.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGHDsYaaTQdzVR4XBR6miu
@matt-edmondson matt-edmondson changed the title Take the two SonarCloud findings from the Quantity type Make a quantity default compile, and take the two SonarCloud findings Sep 14, 2026
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit f0adaf7 into main Sep 14, 2026
12 checks passed
@matt-edmondson
matt-edmondson deleted the claude/blissful-euler-fzuap2 branch September 14, 2026 06:48
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.

2 participants