Rocq (9.0)
This assessment applies the coupling account — coupling as access to a shared resource, and the coupling floor [1], [2] — and the knowledge-embodiment theorem [3]; the language is assessed against its official reference [4].
1 Assessment
This page assesses Rocq in five parts: core coupling — what the language’s own constructs force; ecosystem coupling — what the surrounding platform, tooling, and community cost; engineering readiness — whether the artifact can be reproduced, verified, observed, worked in quickly, connected to other languages, and governed openly; the profile — the unscored facts a score cannot express; and the scoring detail — the mechanism marks and the arithmetic behind every score. A ✅ bullet marks a construct that helps. A ⚠️ or ❌ bullet marks a cost; the scoring model does not price every cost named here.
Core coupling 85/100 · Ecosystem coupling 69/100 · Engineering readiness 49/100
1.1 Core coupling
1.1.1 Type
- ✅ Dependent types decouple a specification from its implementation: A type may mention a value, so a sorted list or a length-indexed vector is a type and a term of that type is the proof that the specification holds
- ✅ The Curry–Howard correspondence equates propositions with types: A proposition is a type and a proof is a program, so logic and computation are written in one language
- ✅ Inductive types define the data and the proofs over it together: An
Inductivedeclaration fixes the constructors, and recursion over them is checked for coverage - ✅ The universe hierarchy stratifies types:
Propholds propositions,Setholds program data, andTypeholds types, so a type cannot contain itself - ✅ Type classes and records express an interface: A
Classor aRecordstates a structure and instance resolution selects the implementation, so reuse does not require inheritance - ⚠️ Definitional equality is the checker’s equality: Two terms that are equal only up to a lemma are not interchangeable without a rewrite, so an implementation must be shaped to compute the way the checker reduces
1.1.2 Construction
- ✅ The logic core is pure: A Gallina term has no side effect, so building a value cannot change shared state
- ✅ The tactic language is separate from the term it builds: A proof script constructs a Gallina term, and the kernel checks that term, so the proof strategy and the proof object are distinct artifacts
- ✅ Definitions are checked terms:
DefinitionandFixpointeach name a term that the kernel type-checks before it is used - ✅ Modules and functors confine names: A
Module Typestates a signature and aModuleimplements it, so a name is reachable only through its path - ✅ Extraction separates verified construction from the runtime:
Extractionemits OCaml, Haskell, or Scheme, so verification is decoupled from the implementation language - ⚠️ Totality is required: Every
Fixpointmust be shown to terminate, so a construction that is correct but not obviously decreasing needs a measure or a well-founded relation
1.1.3 Memory
- ✅ The logic core names no memory: A Gallina term has no address, no allocation, and no free operation, so a proof cannot couple to a memory layout
- ✅ Collection belongs to the runtime: The checker is an OCaml program with its own collector, and the extracted program uses its target language’s collector
- ✅ Reduction strategy is a tactic choice:
cbn,cbv,lazy,vm_compute, andnative_computeselect how a term is reduced, so checking cost is stated where it is needed - ⚠️ A large reduction consumes memory without a visible allocation: A
vm_computeornative_computeover a large term can exhaust memory while the source names no allocation - ⚠️
native_computecompiles a module through OCaml: It evaluates the term through code the OCaml compiler produced at proof time, trading the kernel’s own reduction for speed
1.1.4 Error
- ✅ A wrong proof is a type error: A term that does not inhabit the goal is rejected when it is checked, before any extracted code runs
- ✅ Tactic failure is a structured signal:
Ltaccombinators such astry,repeat,first, andprogressbranch on success and failure, so a tactic script has a recovery path - ✅
Failasserts that a command is rejected: A development can test that a wrong proof fails, which keeps a tactic honest - ✅
Qedruns the kernel check andDefinedrecords the term: The sealing decision is explicit at the end of a proof - ⚠️
Admittedandadmitleave a gap the checker accepts: A development can be declared complete with an unproved lemma, so the guarantee holds only if the development contains none - ⚠️
Axiom,Parameter, andHypothesisadd an assumption without a proof: The soundness of a result is relative to the axiom set it used
1.1.5 Concurrency
- ✅ The logic core is sequential: A Gallina term is a pure value, so there is no shared mutable state in the language to race
- ✅ A development is checked file by file in parallel:
coq_makefile -jandrocq makefile -jcompile independent.vfiles in separate processes - ✅ Asynchronous proofs run in a worker process:
-async-proofs ondelegates a proof to another process, so a document and the proof that fills it are decoupled - ⚠️ The tactic monad threads one proof state: A tactic acts on the current goal, so the tactics in a script are ordered even though the resulting term is pure
- ⚠️ Parallel checking is a tool option, not a language guarantee: An interactive session with
-async-proofs offis sequential, and the option is the user’s choice
1.1.6 Platform
- ❌ Rocq is not a general-purpose programming language: A term is written to be checked, and Gallina has no I/O, no foreign-function call, and no runtime of its own (P1)
- ❌ A deployed program exists only in the extraction target:
Extractionemits OCaml, Haskell, or Scheme, so one development reaches three ecosystems but the verified artifact runs only as a program in another language (P1) - ✅ The checker is an ordinary OCaml program: It builds and runs on the platforms OCaml supports, including Linux, macOS, and Windows
- ⚠️ The OCaml toolchain is required to build the checker: A plugin or a
native_computebuild depends on the OCaml environment, not only on Rocq itself
1.1.7 Trade-offs (not coupling)
- Dependent types trade automation for certainty: The specification lives in the type, and every refinement obligation is discharged by a tactic or by hand
- The ecosystem is small by scope: Rocq targets verification and mathematics, so a general-purpose library set is out of scope rather than missing
- The academic audience is the intended one: The domain mark records a scope decision, not a defect of the language
- Tactic scripts are a workflow choice:
Ltac,Ltac2, andssreflectare ways to construct a term, and a proof can also be written directly as a term Properasure is a deliberate design: A proof inPropis erased from the extracted program, so its cost is a checking cost rather than a runtime cost- Totality is required for a consistent logic: The termination obligation is the price of using one language for proofs and for programs
1.2 Ecosystem coupling
1.2.1 Performance
- ✅ The measured workload is proof checking: The kernel checks a term once, so the checking algorithm, not a program’s runtime, sets the cost
- ✅ Independent files are checked in parallel:
-jand-async-proofsspread a build across the available cores - ✅ A heavy reduction can run as compiled code:
native_computeevaluates a term at the speed of compiled OCaml - ✅ Extracted code runs at the target language’s speed: The deployed program’s performance is the target compiler’s concern
- ⚠️ Checking time grows with the proof: A large
vm_compute, a deepinduction, or a longautosearch can take minutes, and the cost is paid on every rebuild
1.2.2 Ecosystem
- ❌ The ecosystem is small and centred on academia: Outside the standard library,
mathcomp, and the Rocq Platform, the set of maintained packages is thin (Ec3) - ✅
opaminstalls Rocq, its libraries, and its plugins: The OCaml package manager is the distribution channel - ✅ The Rocq Platform pins a compatible set: A Platform release fixes versions of libraries and plugins that are known to work together
- ✅ The landmark libraries are mature:
mathcomp(Mathematical Components),stdpp, andCompCertare long-lived and actively maintained - ⚠️ A plugin extends the checker from inside: An OCaml plugin reaches the engine directly, which is powerful and also couples the plugin to a Rocq version
1.2.3 Evolution
- ✅ The rename from Coq to Rocq preserved compatibility: Rocq 9.0 continued to accept the
Coq.*module paths and thecoq*command names, so an existing development kept checking - ✅ A release is versioned and pinned:
opamrecords the Rocq version and the library versions a development was checked against - ✅ Deprecation precedes removal: A renamed tactic or lemma warns before it stops working
- ✅ The changelog names each change: A release records the renamed lemmas and tactics with their replacements
- ⚠️ Library and tactic names do move between releases: A development that pins no version may need edits when it is checked under a later Rocq
1.2.4 Domain
- ❌ The domain is formal verification and mathematics: The language states and checks proofs, and it is not chosen for general software work (D1)
- ✅ It is a strong fit for the domain it targets: Machine-checked mathematics and verified software are what the system is built to do
- ✅ The CompCert verified C compiler is a landmark result: A realistic C compiler was proved correct in Coq, which is evidence that the domain fit works at scale
- ✅ Critical cryptography and kernel components have been verified in it: Rocq has been used to verify cryptographic primitives and operating-system kernel components
- ✅ Extraction bridges to an industrial artifact: A verified algorithm is extracted to OCaml or Haskell and then deployed
- ⚠️ A proof of a program is not the program: The extracted code is correct relative to the extracted semantics, and a declared axiom weakens the guarantee
1.2.5 Learning
- ❌ The learning curve is very steep: Dependent type theory, universes, and the calculus of inductive constructions must be understood before a nontrivial development can be written (L1)
- ❌ Tactic scripting is a second language:
Ltac/Ltac2and thessreflectidioms are a distinct skill from writing a term - ✅ A first proof is short to write:
intros,reflexivity, andQedcomplete a small example in the first session - ✅ The reference material is thorough and maintained: The Rocq reference manual, the Software Foundations course, and the mathcomp book are stable resources
- ⚠️ An error message must be read against the goal state: The checker reports a goal and a term, and interpreting the report takes practice
1.2.6 Syntax
- ✅ The core grammar is small: A term is an application, a
fun, amatch, or alet, and the proof language is a sequence of commands - ✅
Notationand scopes localise a symbol: A notation applies only where its scope is open, so+can mean different things in different developments - ✅ Inductive and record declarations read as their structure:
Record point := { x : nat; y : nat }names the fields in one line - ✅ Proof bullets give a proof a tree shape:
-,+,*, and{ ... }nest the goals, so the structure is visible - ⚠️ Notation interaction is local knowledge: Two declarations for the same infix symbol, with associativity and precedence levels, can parse a term in a way the reader does not expect
1.2.7 Testing
- ✅ Checking is the test of the proved property: A development that compiles has been checked by the kernel, so the property needs no separate suite
- ✅
Qedseals a proof and runs the kernel check: The term is re-checked at sealing, independently of the tactics that built it - ✅
FailandSucceedtest a command’s outcome: A regression test can require that a specific wrong proof is rejected - ✅
Examplegives an inline test: An anonymous lemma checks a claim at the point where it is stated - ✅
coqdocrenders a checked example into the documentation: A documented example is the same checked term - ⚠️ Only the stated property is checked: An
Admittedlemma or anAxiomis accepted on trust, so the guarantee holds only over the proved fragment
1.2.8 Security
- ✅ The kernel check gives the strongest assurance available for the stated property: A
Qedterm is checked against the calculus, so the result holds as long as the kernel is trusted - ✅ Gallina has no memory operation to misuse: There is no pointer arithmetic and no manual free in the logic core
- ✅
native_computeis opt-in: The compiled reduction is selected explicitly and is disabled by default, so the kernel’s own reduction remains the default path - ⚠️ The trusted base includes the kernel, the extraction, and any axiom: A kernel defect, an extraction defect, or a declared axiom is outside the proof
- ⚠️ Extracted code inherits the target language’s safety: An OCaml or Scheme program is subject to that runtime’s own model
1.3 Engineering readiness
1.3.1 Reproducibility
- ❌ Builds are not byte-reproducible by default.
- ❌ Dependencies resolve without a lock by default.
1.3.2 Supply chain
- ⚠️ Published packages carry no signed provenance by default.
- ⚠️ The package registry is a flat name space.
1.3.3 Observability
- ⚠️ No stable tracing and metrics standard.
- ⚠️ The standard library has no structured logging.
1.3.4 Feedback
- ✅ No charged mechanism in this dimension.
1.3.5 Interop
- ❌ No general foreign-function interface.
- ⚠️ No maintained portable target.
1.3.6 Governance
- ✅ No charged mechanism in this dimension.
1.4 Profile
Unscored, and kept separate from every score on purpose. The profile records what a mechanism price cannot express: what a running program costs, how well a coding model and an agent work in the language, and whether a safety-critical path exists.
1.4.1 Energy and cost
What this axis asks: what does a running program cost in energy and time?
1.4.2 AI and agent readiness
What this axis asks: how well does a coding model and an agent work in this language?
- ❌ Sparse training data: models write it unreliably [8].
1.4.3 Safety certification
What this axis asks: is there a certified or standards-qualified path to a safety-critical system?
- ⚠️ No certified or standards-qualified path for safety-critical systems.
1.5 Scoring detail
1.5.1 Core coupling Dimensions
| Dimension | Mechanism | Description | Present | Cost |
|---|---|---|---|---|
| Type | T1 |
dynamic no static check | — | 0 |
T2 |
weak static | — | 0 | |
T3 |
dynamic/duck dispatch | — | 0 | |
T4 |
no sum types | — | 0 | |
T5 |
no generics | — | 0 | |
T6 |
no namespaces | — | 0 | |
T7 |
type erasure/reflection | — | 0 | |
T8 |
operator overloading | — | 0 | |
T9 |
inheritance required for polymorphism | — | 0 | |
T10 |
no null-safety | — | 0 | |
T11 |
no module boundary | — | 0 | |
T12 |
no effect tracking | — | 0 | |
T13 |
async/sync colouring | — | 0 | |
T14 |
unchecked foreign boundary | — | 0 | |
| Type subtotal | 0 | |||
| Construction | C1 |
global mutable state by default | — | 0 |
C2 |
no immutability by default | — | 0 | |
C3 |
constructors coupled to allocation | — | 0 | |
C4 |
no constructor/validation | — | 0 | |
| Construction subtotal | 0 | |||
| Memory | M1 |
manual deallocation | — | 0 |
M2 |
GC non-deterministic pauses | — | 0 | |
M3 |
no RAII | — | 0 | |
M4 |
no ownership model | — | 0 | |
| Memory subtotal | 0 | |||
| Error | Er1 |
no structured path | — | 0 |
Er2 |
unchecked exceptions only | — | 0 | |
Er3 |
errors ignored/non-exhaustive | — | 0 | |
Er4 |
no composable result type | — | 0 | |
| Error subtotal | 0 | |||
| Concurrency | K1 |
GIL/no parallel | — | 0 |
K2 |
shared mutable state default | — | 0 | |
K3 |
manual sync no race detection | — | 0 | |
K4 |
no structured concurrency | — | 0 | |
K5 |
no primitives | — | 0 | |
| Concurrency subtotal | 0 | |||
| Platform | P1 |
cannot function outside one vendor/domain | ✅ | −15 |
P2 |
single-vendor but other uses | — | 0 | |
P3 |
legacy/discontinued platform | — | 0 | |
| Platform subtotal | −15 |
Core Dimensions score: 85/100 — total cost = −15 (per-dimension subtotals are capped at −15; an uncapped cost is shown in parentheses where the cap bites).
1.5.2 Ecosystem coupling Dimensions
| Dimension | Mechanism | Description | Present | Cost |
|---|---|---|---|---|
| Performance | R1 |
interpreted no AOT/JIT | — | 0 |
R2 |
GC pauses | — | 0 | |
R3 |
JIT warmup | — | 0 | |
| Performance subtotal | 0 | |||
| Ecosystem | Ec1 |
no package manager | — | 0 |
Ec2 |
fragmented tooling | — | 0 | |
Ec3 |
small/niche/discontinued | ✅ | −8 | |
Ec4 |
proprietary | — | 0 | |
Ec5 |
platform-locked tooling | — | 0 | |
Ec6 |
monoculture | — | 0 | |
Ec7 |
legacy burden | — | 0 | |
| Ecosystem subtotal | −8 | |||
| Evolution | V1 |
breaking changes | — | 0 |
V2 |
frozen | — | 0 | |
V3 |
discontinued | — | 0 | |
V4 |
glacial standards | — | 0 | |
| Evolution subtotal | 0 | |||
| Domain | D1 |
domain/vendor lock-in | ✅ | −15 |
D2 |
poor domain fit | — | 0 | |
D3 |
framework forces architecture | — | 0 | |
| Domain subtotal | −15 | |||
| Learning | L1 |
steep | ✅ | −8 |
L2 |
large surface/multi-paradigm | — | 0 | |
L3 |
sparse docs | — | 0 | |
| Learning subtotal | −8 | |||
| Syntax | S1 |
verbose | — | 0 |
S2 |
inconsistent | — | 0 | |
S3 |
punctuation-heavy | — | 0 | |
| Syntax subtotal | 0 | |||
| Testing | G1 |
weak tooling | — | 0 |
G2 |
poor debugging | — | 0 | |
G3 |
runtime-only errors | — | 0 | |
| Testing subtotal | 0 | |||
| Security | Q1 |
memory-unsafe | — | 0 |
Q2 |
dynamic/weak typing risk | — | 0 | |
Q3 |
known vulnerability/injection | — | 0 | |
| Security subtotal | 0 |
Meta Dimensions score: 69/100 — total cost = −31 (per-dimension subtotals are capped at −15; an uncapped cost is shown in parentheses where the cap bites).
1.5.3 Engineering readiness Dimensions
| Dimension | Mechanism | Description | Present | Cost |
|---|---|---|---|---|
| Reproducibility | Y1 |
build not reproducible | ✅ | −8 |
Y2 |
dependencies not pinned | ✅ | −8 | |
| Reproducibility subtotal | −15 (−16) | |||
| Supply chain | Y3 |
no signed provenance | ✅ | −8 |
Y4 |
registry without namespacing | ✅ | −4 | |
| Supply chain subtotal | −12 | |||
| Observability | Y5 |
no stable tracing standard | ✅ | −8 |
Y6 |
no structured logging | ✅ | −4 | |
| Observability subtotal | −12 | |||
| Feedback | Y7 |
slow build | — | 0 |
Y8 |
no fast in-editor analysis | — | 0 | |
| Feedback subtotal | 0 | |||
| Interop | Y9 |
no foreign-function interface | ✅ | −8 |
Y10 |
no portable target | ✅ | −4 | |
| Interop subtotal | −12 | |||
| Governance | Y11 |
single-vendor governance | — | 0 |
Y12 |
closed specification | — | 0 | |
| Governance subtotal | 0 |
Readiness Dimensions score: 49/100 — total cost = −51 (per-dimension subtotals are capped at −15; an uncapped cost is shown in parentheses where the cap bites).
Verdict: Rocq yields low core coupling for the narrow work it is built for: dependent types put the specification in the type, tactic scripts are separate from the terms they build, extraction decouples verification from the implementation language, and the logic core is pure and total. The core score loses only through P1, because the language does not function outside the domain of formal proof. The platform cost is the price of that focus — a small academic ecosystem, a domain lock-in to verification, and one of the steepest learning curves here. Main strengths: kernel-checked certainty, the CompCert landmark result, and extraction as the bridge to OCaml, Haskell, or Scheme; main weaknesses: the narrow domain, the thin ecosystem, and the depth of type theory and tactic knowledge required.
The formal development. The definitions, theorems, and proofs behind this page are published in:
- On the Nature of Coupling: All Coupling as Shared Resource Access — Zenodo, 2026 — doi:10.5281/zenodo.21925122
- Coupling as a Consequence of Cohesion: Decomposition, the Coupling Floor, and Domain-Imposed Coupling — Zenodo, 2026 — doi:10.5281/zenodo.21925201
- On the Nature of Cohesion: Cohesion as Correctness Relative to a Partitioning Rule — Zenodo, 2026 — doi:10.5281/zenodo.21703193