A side-by-side comparison of syntax and semantics. Python is a far more mature language with a larger ecosystem. Where Vary has something built in, Python typically has third-party equivalents.
For a property-testing-specific comparison, see Hypothesis comparison.
| Feature | Python | Vary |
|---|---|---|
| Typing | Dynamic, optional hints | Static, enforced at compile time |
| Execution | Interpreted | Compiled to JVM bytecode |
| Variables | x = 42 (always mutable) | let x = 42 / mut x = 0 |
| Type annotations | Optional | Parameter types required |
| Null handling | Anything can be None | Only T? types can be None |
| Strings | str | Str |
| Booleans | True / False | True / False (same) |
| Collections | list, dict, set | List[T], Dict[K, V], Set[T] |
| Data types | @dataclass | data keyword |
| Inheritance | Multiple inheritance | No inheritance; interface + implements |
| Enums | enum.Enum | enum with payloads and exhaustive match |
| Pattern matching | match/case (3.10+) | match/case with guards and or-patterns |
| Concurrency | async/await, threads | spawn/join |
| Lambdas | lambda x: x + 1 | lambda x: Int: x + 1 (typed) |
| Error handling | try/except/raise | Same syntax |
| Contracts | No built-in (third-party: icontract, deal) | Built-in in {} / out (r) {} / old() |
| Imports | from x import y | Same, plus aliases |
| Web/HTTP | Flask, Django | expose Interface via http |
| Testing | pytest, unittest | Built-in test DSL + observe |
| Mutation testing | Third-party (mutmut) | Built-in vary mutate |
| Runtime | CPython / PyPy | JVM (Eclipse Temurin 25) |
Python runs on CPython (or PyPy). Vary compiles to JVM bytecode and runs on the Java Virtual Machine. This has practical consequences:
| Area | Python | Vary |
|---|---|---|
| Startup time | Fast (tens of ms) | Slower (hundreds of ms due to JVM cold start) |
| Long-running performance | Good, but limited by GIL for CPU-bound threads | JIT-compiled over time; real multithreading |
| Memory model | Reference counting + cycle collector | Garbage collected (G1, ZGC, etc.) |
| Integer size | Arbitrary precision | 64-bit (long) |
| Float size | 64-bit (double) | 64-bit (double) |
| Collections | Native Python objects | Java ArrayList, HashMap, HashSet under the hood |
| Package ecosystem | pip, PyPI (500k+ packages) | No package manager yet; stdlib only |
Python starts faster. The JVM is a better fit for long-running services where JIT warmup pays off and real threading matters.
Each conflicts with static analysis, predictable compilation, or explicit control flow.
| Feature | Why excluded |
|---|---|
| Metaclasses | Makes class definition non-deterministic; breaks static analysis |
| General-purpose decorators | Hides control flow; conflicts with explicit execution |
*args / **kwargs | Undermines explicit signatures and static typing |
Context managers (with) | Requires implicit protocol hooks |
Generators (yield) | Hidden state machines; complicates bytecode generation |
| C extensions | Incompatible with JVM bytecode |
| Dynamic import hooks | Breaks compile-time dependency analysis |
| Monkey patching | Violates immutability guarantees |
Walrus operator (:=) | Hides mutation inside expressions |
Wildcard imports (from x import *) | Makes static analysis non-local |
Bare except: | Swallows unexpected failures |