Dafny spec to clojure.spec Transpiler
Table of Contents
1. Motivation
compiled a method with requires x>0 / ensures r>0 to Java (dafny build --target:java, Dafny 4.11.0) and called it from a Java driver with x=-5. It did not crash -- it silently returned -5, violating the postcondition Dafny proved under the assumption. "may crash" is wrong; the actual mechanism is a silent postcondition violation.
The Dafny-Clojure interop article covers the JVM boundary:
Dafny compiles to Java, Clojure calls it. But Dafny's requires and
ensures clauses are ghost-erased at compile time – the JAR carries
no trace of the preconditions. If Clojure passes invalid data across
the boundary, the "verified" code does not crash – it silently
returns a result that violates the postcondition Dafny proved under
its assumptions.
This note explores the inverse direction: parse .dfy source and
generate clojure.spec.alpha definitions that enforce Dafny's
contracts at runtime.
2. The trust gap
compiled a minimal .dfy method with requires/ensures to Java (Dafny 4.11.0) -- the generated __default.java has no precondition or postcondition check in the method body, confirming "(no P check)" / "(no Q check)".
Dafny source --> JAR (ghost-erased) --> Clojure caller requires P(x) (no P check) passes x without P? ensures Q(r) (no Q check) trusts r blindly?
The spec transpiler closes this: requires P(x) becomes (s/def ::x P-spec).
3. Scope
- Parse
requires,ensures,invariantclauses from.dfyfiles - Generate
clojure.spec.alphaormallischemas - Handle: numeric ranges, string predicates, sequence length, set membership
- Out of scope: quantifiers (
forall,exists), ghost variables, heap predicates
4. Open questions
- Should the output be spec or malli? The interop article uses malli for the codec schemas.
- How to handle Dafny's
seq<char>vs Clojure'sString– the type mapping table in the interop article is the starting point. - How to handle
modifiesclauses – these have no spec equivalent.
5. Related
- Dafny-Clojure JVM Interop (parent article, SG-2 gap)
- Lean 4 codec proofs (the type-level version of this)
- Type systems, one tool four ways (comparative perspective)
- clojure.spec, since 2016 (spec.alpha vs malli as the output target)