Comparisons

Related languages

Origins

Vary started out Python-shaped. The early syntax borrowed def, for...in, if/elif/else, import and from...import directly. If you had written Python, the first version of Vary looked familiar.

It diverged quickly. Static types are enforced at compile time. Blocks use braces. Mutation testing is a compiler command. The test runner is built into the language. Enums carry payloads. None of this exists in Python.

If terms like ghost code, proof obligations, invariants, or exhaustive match are unfamiliar, see the Glossary.

Python

Python showed that code can be readable without being verbose. Short keywords, minimal ceremony, no semicolons.

AreaPythonVary
TypingDynamic, optional hintsStatic, enforced at compile time
ExecutionInterpretedCompiled to JVM bytecode
Variablesx = 42 (always mutable)let x = 42 / mut x = 0
Null handlingAnything can be NoneOnly T? types can be None
Data types@dataclassdata keyword
Enumsenum.Enumenum with payloads and exhaustive match
Testingpytest, unittestBuilt-in test DSL + observe
Mutation testingThird-party (mutmut)Built-in vary mutate

For a full comparison, see Python comparison.

Eiffel

Eiffel pioneered Design by Contract: preconditions, postconditions, and class invariants checked at runtime. Vary's contract system (in/out/old) draws directly from Eiffel's model.

AreaEiffelVary
Preconditionsrequire blockin {}
Postconditionsensure blockout (result) {}
Entry-state captureold exprold(expr)
Class invariantsinvariant blockinvariant {} on classes and data types
Contract enforcementRuntime, can be disabled per buildRuntime, always on in vary mutate
Mutation integrationNoneContract violations are mutation kill signals

Eiffel treats contracts as documentation and correctness aids. Vary treats them as oracle surfaces for mutation testing. A contract that fails under mutation means the program is well-constrained. A contract that no mutation can break is too weak. Contracts in Vary exist to make vary mutate more powerful, not to prove formal correctness.

D

Two D ideas influence Vary: the pure function qualifier and built-in contract syntax.

AreaDVary
Puritypure qualifier, compiler-enforcedpure def, compiler-enforced
Contractsin {} / out {} blocks on functionsin {} / out (result) {}
Contract scopePreconditions, postconditions, invariantsPreconditions, postconditions, old(expr)
Mutation testingNone built inBuilt-in vary mutate
Compilation targetNative machine codeJVM bytecode

D enforces purity for safe parallelism and optimization. Vary enforces purity to improve mutation testing signal. A pure def guarantees no hidden state, so surviving mutants point to genuine gaps in contracts or tests rather than side-effect interference. D proved that purity enforcement is practical in a mainstream-style language. Vary applies it to a different problem.

Dafny

Dafny is a verification-aware language. Programs are proved correct at compile time using an SMT solver (Boogie/Z3). Contracts written in Dafny are not runtime checks: they are static proof obligations that must hold before the compiler will emit code.

AreaDafnyVary
VerificationStatic proof via SMT solver (Boogie/Z3)Runtime contracts + mutation testing
Preconditionsrequiresin {}
Postconditionsensuresout (result) {}
Pre-state captureold(expr)old(expr)
Invariantsinvariant on classes and loopsinvariant {} on classes and data types
Terminationdecreases clause (compiler-checked)Not enforced
Frame controlreads / modifies clausesNo frame specifications
Ghost codeGhost variables and functions (erased at compile time)No ghost constructs
Null handlingT? for nullable typesT? for nullable types
Variablesvar (mutable) / const (immutable)mut (mutable) / let (immutable)
Compilation targetsC#, Java, JavaScript, Go, C++JVM bytecode
Mutation testingNone built inBuilt-in vary mutate
TestingSpecifications replace most testsBuilt-in test DSL + observe

Dafny proves that a function is correct for all inputs. Vary does not attempt formal proofs. Instead it checks contracts at runtime and uses mutation testing to measure how well those contracts and tests constrain behaviour. A surviving mutant in Vary means a gap exists. An unproved postcondition in Dafny means the solver cannot confirm correctness.

The two approaches fail differently. Dafny proofs can require heavy annotation (decreases clauses, loop invariants, lemma functions) to satisfy the solver. Vary contracts are lighter to write but weaker: they catch violations only when exercised by tests or mutants, not for all possible inputs. Dafny targets provable correctness. Vary targets confidence through fault injection.

← Hypothesis comparison