Skip to content

Find out whether the quantities reach seven languages, not two - #225

Merged
matt-edmondson merged 2 commits into
mainfrom
claude/bold-planck-mxarux
Sep 13, 2026
Merged

Find out whether the quantities reach seven languages, not two#225
matt-edmondson merged 2 commits into
mainfrom
claude/bold-planck-mxarux

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Answer: five of seven. The two that fail do so for reasons now recorded upstream, and neither is fixable here.

This is the question the ktsu.Coder AST work was for. It is answered by building the thing and running it, not by reading the AST and judging it expressive.

The bump this needed first

ktsu.Coder was pinned at 3.6.0, which predates every node the question depends on — CallExpression, ConditionalExpression, TypeParameter, TypeConstraint, PropertyDeclaration, Annotation, ClassDeclaration.Interfaces, and GoGenerator itself. 3.11.0 has all of them.

Worth stating plainly because it is the kind of thing that silently isn't true: the C++ projection needed no change across those five versions, and its 27 tests — the g++ and clang++ compiles among them — pass unaltered.

The probe

SevenTargetProjectionTests builds one quantity as a neutral AST and writes it in all seven targets. The quantity is the magnitude form of Length, read from the real dimensions.json rather than a fixture, for the reason the C++ tests do it: a probe run against something invented answers a question nobody asked.

The neutral shape is the whole of what a generated magnitude is and no more — a record struct over a storage type, with a value and a unit factory.

C# comes out as exactly what QuantitiesGenerator writes today:

public readonly partial record struct Length<T> : IVector0<Length<T>, T>
    where T : struct, INumber<T>
{
    public T Value { get; init; }
    public static Length<T> FromMeter(T value) { return Create(value); }
}

That is the result worth having. The AST reaches the declaration this repository already generates, so what the other six targets do is a question about those languages rather than about the model.

C++, Rust, C and JavaScript are each right for their own reasons: the two with type parameters carry the storage type onto the declaration (template <typename T>, struct Length<T: INumber<T>>), and the two without write it down rather than inventing one — the same decision CompileTimeAssertion gets in the targets with no assertion.

What it found

Two targets write source their own toolchain refuses. Both were confirmed by running that toolchain, not by reading the output:

Target Output Toolchain says
Go type Length struct with no parameters, then func LengthFromMeter(value T) Length[T] go vet: undefined: T
Python class Length(IVector0[Length[T], T]) NameError: name 'Length' is not defined

Go's is an internal disagreement: a generic type is deliberately written down rather than emitted, which is a defensible decision, but the constructor was not given the same treatment — so it returns Length[T] from a Length that takes no parameters, and the field's type T is undefined. ktsu-dev/Coder#63.

Python's is that a base list is evaluated eagerly, so the self-type idiom every quantity here is declared with cannot be a Python base at all. ktsu-dev/Coder#64.

Both are pinned rather than skipped. The tests assert that the broken output is what comes out, so the day either is fixed upstream the test fails and is updated to assert the fix — rather than a skip nobody revisits.

Where it lives, and why that is itself a finding

Semantics.Cpp.Test, because that is where the reader of dimensions.json is. The name is wrong for it and that is the point: QuantityMetadata and MetadataProjection decide nothing about C++, and would have to be shared the way Semantics.Vocabulary already is before a neutral projection could be a project of its own. That is the next structural step if this is worth pursuing, and it is a decision about the product surface rather than one to take in passing.

33/33 C++ projection tests and 1139 Semantics tests pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QGCMUrT3jBgmANHNHcPmBf


Generated by Claude Code

Answer: five of seven, and the two that fail do so for reasons recorded
upstream rather than anything here.

## The bump this needed first

`ktsu.Coder` was pinned at 3.6.0, which predates every node the question
depends on — `CallExpression`, `TypeParameter`, `TypeConstraint`,
`PropertyDeclaration`, `Annotation`, `ClassDeclaration.Interfaces`, and the
Go generator itself. 3.11.0 has all of them. The C++ projection needed no
change across those five versions and its 27 tests, g++ and clang++
compiles included, pass unaltered.

## The probe

`SevenTargetProjectionTests` builds one quantity — the magnitude form of
`Length`, read from the real `dimensions.json` rather than a fixture — as a
neutral AST, and writes it in all seven targets. The shape is the whole of
what a generated magnitude is: a record struct over a storage type, with a
value and a unit factory.

C# comes out as exactly what `QuantitiesGenerator` writes today. That is the
result worth having: the AST reaches the declaration this repository already
generates, so what the other six do is a question about those languages
rather than about the model.

C++, Rust, C and JavaScript are each right for their own reasons — the two
with type parameters carry the storage type, the two without write it down
rather than inventing one.

## What it found

Two targets write source their own toolchain refuses, and both were
confirmed by running that toolchain rather than by reading the output:

- Go: `go vet` says `undefined: T`. A generic type is deliberately written
  down rather than emitted, and the constructor was not given the same
  treatment, so it returns `Length[T]` from a `Length` that takes no
  parameters. ktsu-dev/Coder#63.
- Python: `NameError: name 'Length' is not defined`. The self-type idiom
  every quantity is declared with cannot be a Python base, because a base
  list is evaluated eagerly. ktsu-dev/Coder#64.

Both are pinned rather than skipped, so fixing either upstream fails the
test here and it is updated to assert the fix.

## Where it lives

`Semantics.Cpp.Test`, because that is where the reader of `dimensions.json`
is. That is the finding about this repository rather than about Coder:
`QuantityMetadata` and `MetadataProjection` decide nothing about C++ and
would have to be shared the way `Semantics.Vocabulary` already is before a
neutral projection could be a project of its own.

33/33 C++ projection tests and 1139 Semantics tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QGCMUrT3jBgmANHNHcPmBf
A find-and-replace left the tail of the sentence it replaced, so the
Python test's remarks read "A string annotation or / A string in the base
list is the fix". Nothing behavioural; the sentence now says one thing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QGCMUrT3jBgmANHNHcPmBf
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit b1c7adf into main Sep 13, 2026
13 checks passed
@matt-edmondson
matt-edmondson deleted the claude/bold-planck-mxarux branch September 13, 2026 03:02
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