I’d like to create a Representer for the V track (issue exercism/vlang#43).
I’ve built a working prototype and would rather not guess at the process. Per the “creating a Representer” docs, step 3 is to start a topic here so the repo can be set up. A few questions, because I’d rather get them right than rework the repo afterwards:
- Repo location. Should you create
exercism/vlang-representer, or should I fork an existing one?exercism/zig-representeris the closest model I found: small, written in shell rather than the track’s own language, and it wraps the language’s own formatter rather than parsing anything itself. - Test runner version. The V track is still on test runner v1 (#45, #46). Is a representer dependent on v2 or v3, or is v1 fine? This decides whether #43 can be closed on its own.
- The input directory.
bin/run.shin the zig representer reads<solution-dir>/.meta/config.jsonto learn the solution’s filename. Is that actually what the website provides? It matters for V specifically, becausesecret-handshake’s solution issecret_handshake.vand cannot be derived from the slug. The prototype falls back to globbing if the file is absent, but I’d rather rely on the real contract. - Depth of normalization. The prototype uses
v fmtand nothing else. Known gaps: comments are preserved, and local names are not replaced with placeholders, so solutions differing only in those still get separate representations. Isv fmtalone worth having for V, or would you want the identifier renaming too? I lean towards shippingv fmtfirst and adding renaming later, since the gap is visible and separable.
The prototype: GitHub - metif12/vlang-representer: Representer for the Exercism V track · GitHub
The design choice worth arguing about: the representation is the output of v fmt, and nothing else. V accepts both "foo" and 'foo' for the same string and leaves either style standing, so two solutions that differ only in quoting are two representations for mentors to review separately today. v fmt also normalizes indentation to tabs and aligns consecutive struct fields. That is the bulk of the spurious uniqueness in this track.
The reason for stopping there is that v fmt is semantics-preserving, and the interface spec’s hard requirement is that two genuinely different solutions must never share a representation. Anything stripped afterwards has to be provably safe: removing blank lines, for instance, would rewrite multi-line string literals, so a solution holding 'a\n\nb' and one holding 'a\nb' would collapse onto one representation.
Two things worth knowing: the compiler has to be pinned, hard — the output of v fmt is the representation, so a new V release would silently change the representation of every solution already stored, and mentor comments would stop matching. The Dockerfile pins V_VERSION and V_SHA256. And V has no ternary operator, so there is nothing to normalize there — c ? 1 : 2 is not valid V and does not compile; the V way is if c { 1 } else { 2 }, which v fmt formats correctly.
A cold container run, including container start, is about 0.6 s against the 20 second budget. v fmt is about 20 ms per file. 29 fixture assertions pass in the image and on the host.