Main ideas¶
Lucid is a Python-like language sketch that keeps Python easy to read and write, poaches the best ideas other languages already found, and removes the compatibility constraints that keep Python from adopting many of its own best proposals.
Core principle:
Keep Python's directness, make structure explicit, and choose the cleaner
rule when compatibility no longer has to win.
Zero-deprecation¶
Python's deprecations stay supported for several versions before removal, so old designs often outlive their reasons. Lucid cuts that to a one-year cadence, each release shipping LLM upgrade instructions instead of a deprecation period. This freedom is a standing property, not a founding choice: Lucid treats rejected or constrained ideas as open design space by default. See Keyword reference.
Python readability¶
Lucid code stays as easy to read and write as ordinary Python: indentation
matters, definitions are direct, and simple programs need no ceremony
(see Binding, If, For and While).
Where Python lets more than one way survive — three generations of
string formatting, or a named-fields bag as a class, dataclass,
NamedTuple, or TypedDict — Zero-deprecation
lets Lucid pick one and enforce it by construction:
No tuple or namedtuple type picked named records
once, and No % string formatting
picked f-strings once.
Explicit over implicit¶
Python lets behavior happen somewhere other than where you're looking —
__getattr__, descriptors, and metaclasses intercept normal-looking
code, and typing.Protocol grants conformance to code that never asked
for it. Lucid closes these off:
- traits are nominal (No structural traits)
finalandoverridemust be written, never inferred (Explicit overrides)- attribute access has no interception hooks (No descriptors)
- object state is declared directly in the class body, not hidden
behind
__dict__(Classes have visible state) - a factory returns a fully built object, never a partially initialized one (Factory construction)
- a name's visibility is checked, not merely requested by a leading
_Python never enforces (Module-private names)
Java-style single inheritance¶
Python's multiple inheritance overloads one base-class list for shared
state, interfaces, reusable behavior, and MRO — jobs that interfere,
since MRO order can silently change which method a call reaches. Lucid
keeps Java's split instead, naming the non-state-owning kind trait:
one class parent, since only a class owns stored state, but any number
of traits, each free to mix required methods with reusable default
ones — a bodyless member is an obligation, a bodied one is a default,
no marker keyword for either. See Traits and
One class parent.
Checked type relationships¶
A docstring's mutation promise isn't checked at all, and a variance
annotation an author writes by hand can be wrong in a way nothing catches
until a caller depends on it. Lucid's generic parameters carry variance
the checker derives directly from how each is used in its class or
trait's own body — covariant where only produced, contravariant where
only consumed, invariant where both — and re-derives on every check, so
an edit that changes it is caught at whichever call site relied on the
old one, not learned later at runtime. Mutable, read-only, and immutable
views stay visible in the type spelling itself, with T, ~T, !T. See
Generics, Mutability, and
Modern type specification.
Julia-style dynamic dispatch¶
Python's binary operators are single-dispatch on the left operand, so a
second method and a negotiation protocol — __radd__, NotImplemented
— exist only to approximate the two-sided decision a + b needs. Lucid
makes operators ordinary multiple-dispatch functions instead, picking an
implementation from every argument's type at once, staying open to third
parties the same way Dispatch beyond operators already is
for ordinary functions.
Rust-style error handling¶
Python collapses two kinds of failure into one mechanism — raise/
try/except handle both an expected outcome and a broken invariant,
with nothing in a function's signature saying which. Lucid splits the
two: a recoverable failure is an ordinary return type, checked
exhaustively like any other union, with ? as sugar to propagate it;
raise stays, narrowed to broken invariants, unchecked. See
Results and Exceptions.
Kotlin-style function types¶
Python spells a callable's type Callable[[A, B], R], inherited from
fitting a parameter list inside the same generic syntax as every other
type — it reads nothing like the def it describes. Lucid spells it
(A, B) -> R, matching Kotlin: the same -> a def's own return type
already uses, with the same grammar an ordinary signature uses for
names, zoning, or variadic gathering. See Function types.
Toll-free Python 3.13+ interop¶
Alternative implementations of Python (such as PyPy and GraalPy) historically suffered 2x–10x slowdowns when interacting with C extensions because their memory layouts diverged from CPython, requiring costly proxy objects, pointer pinning, and state synchronization.
Lucid targets Python 3.13+ exclusively, aligning its heap object memory layout
directly with CPython's PyObject binary prefix. Passing a Lucid array or
struct to a C extension (such as NumPy or PyTorch) requires no copying, no
proxying, and zero marshaling. Furthermore, by targeting Python 3.13's
free-threading (PEP 703) and immortal objects (PEP 683), Lucid runs
multithreaded code across all CPU cores without the Global Interpreter Lock,
and maps its transitively frozen !T values to immortal objects so that
foreign code never incurs atomic reference-counting contention across threads.
See Casting.
These principles work together: explicit structure and zero-deprecation clear away Python's dynamic ambiguities, letting static typing, multiple dispatch, and toll-free interop achieve native speed without losing Python's readability. The remaining documents specify each mechanism in detail, starting with Binding.