1. Hello, Luce
Install#
On macOS or Linux:
curl -fsSL https://luce.luciaos.com/install.sh | sh && . "$HOME/.local/luce/env"On Windows, in Command Prompt:
curl -fsSLo "%TEMP%\luce-install.cmd" https://luce.luciaos.com/install.cmd && "%TEMP%\luce-install.cmd"or in PowerShell:
irm https://luce.luciaos.com/install.ps1 | iexThis puts the compiler, luce, and the project tool, luc, on your PATH. On macOS and Linux, building a program uses the C toolchain on your machine to assemble and link, so it needs one: the Xcode command line tools on macOS (xcode-select --install) and gcc or clang on Linux; the installer tells you if it is missing. On Windows the compiler assembles and links by itself, so nothing else is needed. Check that it worked:
luce --versionA first program#
Save this as hello.luc:
pub func main(arguments: list[str]) -> int!:
print("Hello, Luce!")
return 0Hello, Luce!
Run it:
luce run hello.lucIf you know Python, most of this reads as you would expect:
- Indentation marks blocks, as in Python: a line ending in
:opens a block indented four spaces. mainis where the program starts. Python runs a file from top to bottom; a Luce program starts atmain, which receives the command-line arguments as a list of strings and returns the exit status. Its signature is always the one above.- Types are written after names, as in Python's type hints, and a function's result type after
->. Unlike Python's hints, they are checked before the program runs: a program with a type error does not start. - The
!inint!means thatmaincan fail. Chapter 7 explains it; until then, everymainin the Tour is written this way. pubmakes a declaration visible outside its file.mainmust bepub.
Running and building#
luce run runs the program straight away, in an interpreter. luce build compiles it to a native executable that runs on its own, without Luce installed:
luce build hello.luc -o hello
./helloThe two print the same thing. Use luce run while you work, and luce build for a program to keep or hand to someone else.
Formatted strings and arguments#
print takes any number of values and separates them with spaces, as in Python. Formatted strings are written as in Python too, with an f before the quote:
pub func main(arguments: list[str]) -> int!:
let language = "Luce"
let year = 2026
print(f"Hello from {language}, {year}.")
print("Arguments:", arguments.length, arguments)
return 0Hello from Luce, 2026. Arguments: 0 []
The braces hold any expression, with Python's format specification after a colon when you want one: {price:.2f}, {count:>5}. One difference from Python: arguments holds only the arguments, without the program's name that Python's sys.argv[0] holds. Run it as luce run hello.luc one two and the second line reads Arguments: 2 [one, two].
Notice also that a list prints its strings without quotes: [one, two], where Python would print ['one', 'two'].
A project#
A single file is enough for a small program. A program with several files or with dependencies is a project, and luc creates one:
luc new greeter --tool --luce
cd greeter
luc runluc new writes three files:
greeter/
package.prisma the project's name, version, kind and dependencies
src/main.luc the entry point
.gitignorepackage.prisma describes the project, much as pyproject.toml does for Python:
#prisma 4.0
def package "greeter" {
str owner = "you"
str version = "0.1.0"
str kind = "tool"
str language = "luce"
str entry = "src/main.luc"
}luc run builds the program into build/greeter and runs it. The other everyday commands:
| Command | What it does |
|---|---|
luc build | build without running; --release optimises |
luc test | run the tests |
luc check | type-check without building |
luc fmt | format the sources |
--tool makes a command-line program, --application a desktop application, and --package a library for other projects to use. Chapter 9 covers projects and dependencies.
The compiler on its own#
For single files, luce works without luc:
| Command | What it does |
|---|---|
luce run file.luc | run it in the interpreter |
luce build file.luc -o out | build an executable; --release optimises |
luce check file.luc | type-check only |
luce test file.luc | run the file's tests |
luce fmt file.luc --write | format the file in place |
Run luce with no arguments for the full list.
Where next#
Chapter 2 covers the building blocks: bindings, numbers and text.