Luce
The application language of the Luce project
Luce is Python's ease with a compiler's guarantees: one integer, one float, text, values that copy, classes that share, memory that manages itself, failure that is visible, and nothing about machines. Everything about machines is Luce Base (base.md), the systems language this compiler is written in and the only door to C. A Luce program reaches Base by import, and it compiles to Base, so every backend, optimiser and target Base has is Luce's.
The language sentence:
Values copy. Classes share. Nothing is freed by hand. Failure is a type. The machine is a Base package away.
The product sentence:
Readable like Python, checked like a compiler, fast like the systems language under it.
This document is the complete contract of the language. base.md is the contract of the language under it, and chapter 16 is the contract between the two. Where an implementation and this document disagree, the document is right and the implementation is a bug; where this document is silent, the behaviour is not promised.
1. Principles#
Eight concepts. Every Luce program is made of bindings, functions and control, values, classes, collections, failure, abstraction, and workers. Arrays, strings, files, sockets and windows are types and libraries built from those; methods are functions inside a type; closures are functions with an environment; iteration is an interface plus for; errors are one value carried by T!; tests are registered fallible functions; packages are modules plus a manifest. Nothing else is a concept.
One number of each kind. int is a 64-bit signed integer and float a 64-bit IEEE double. There is no other width, no unsigned integer, no wrapping or saturating arithmetic, and no bit operation. Code that needs them is Base code.
The machine is elsewhere. Luce has no pointer, span, fixed array, union, allocator, asm, atomic, or foreign declaration. A Base package has all of them and exposes a Luce program only the crossable types of chapter 16. This is what keeps Luce small: a need for the machine is a reason to write a Base package, never a reason to add a feature.
Memory is not the programmer's. Objects are reference-counted and a cycle collector reclaims what counting cannot, exactly Python's model. There is no word for allocation, release, ownership or weakness in the language. Resources close with with.
Failure is visible. A function that can fail says so in its type, a caller handles it or passes it on, and a violated rule is a trap with a source trace, never an exception.
A feature enters only when it removes more complexity than it adds, counting syntax, semantics, the compiler, the runtime, diagnostics, tooling, documentation and what a programmer must remember. When a need appears it is solved at the cheapest correct layer: a diagnostic, a library, a tool, then the language.
Two executions must agree. The interpreter is the definition of behaviour, and the Base the compiler emits must print the same bytes through every generator Base has. A feature is not implemented until they agree on its programs and its traps.