The Scaly Programming Language

Appendix A

The Tools

Scaly comes as three programs: scaly, the tool that runs, builds and tests programs; scalyc, the compiler by itself; and scalyls, the language server an editor talks to. This appendix says how they are installed and what each of them takes.

Installation

The installer — install.sh on macOS and Linux, install.ps1 on Windows (Installing Scaly) — puts everything under ~/.scaly (%USERPROFILE%\.scaly on Windows) and the three commands on your PATH. It needs no administrator rights for that. The standard library and the standard packages — http, https, tls, json, compress, pg, redis and h3 — come with it as sources; a package is compiled the first time a program uses it and kept in ~/.scaly/cache.

Before it fetches anything, the installer shows Scaly's license (MIT, with its disclaimer of warranty) and asks whether you accept it; without that, nothing is installed. Where nobody can answer — a Dockerfile, CI — SCALY_ACCEPT_LICENSE=1 accepts it:

curl -fsSL https://scaly.io/install.sh | SCALY_ACCEPT_LICENSE=1 sh

Ready to run, or built on your machine

For these systems the installer downloads the programs ready to run, which takes a few seconds:

  • macOS 26 on Apple silicon, macOS 15 and newer on Intel

  • Ubuntu 26.04 and newer, on arm64 and x86-64

  • Windows 10 and 11, on x64 and arm64

Building a program needs a C compiler, which links it: Apple's Command Line Tools on macOS, clang on Linux, the Visual Studio Build Tools on Windows. Where it is missing, the installer fetches it, and the system asks for your password (on Windows, for administrator rights) once. On macOS and Linux, SCALY_BUILD_TOOLS=skip leaves that out.

On a macOS or a Linux that is not in the list — an older version, another distribution, or one where the ready-made programs do not start — the installer builds Scaly on your machine instead. Scaly ships its compiler as LLVM IR, the seed (Bootstrap History and the Seed), so that route needs LLVM 21 and takes about half a minute:

brew install llvm@21                                   ; macOS
sudo apt install llvm-21 llvm-21-dev lld-21 clang     ; Ubuntu and Debian

The installer says which of the two routes it takes; SCALY_FROM_SEED=1 asks for the second one anywhere.

Versions, updates, removal

The installer takes the newest version of the toolchain. A version that is out does not change afterwards, so a particular one can be asked for by its number and is the same every time (versions before 0.2.29 are no longer offered for download):

curl -fsSL https://scaly.io/install.sh | SCALY_VERSION=0.2.29 sh

The toolchain's number is its own. The packages it brings — the standard library among them — have theirs, and a program's package scaly 0.2.0 goes on meaning the standard library of whatever toolchain is installed, as long as that is of the same line (Versions, and what publishing means).

Running the installer again replaces the toolchain with the current one. To remove Scaly, delete ~/.scaly and the PATH line the installer added to your shell profile.

scaly

The tool you will use most. Started without arguments it is the interactive session (Trying Things Out); with a verb, it does one of these:

scaly run file [arguments]

Compiles the program in memory and runs it at once, handing it the arguments. Nothing is left on disk.

scaly build file [-o out]

Builds an executable. --release optimises it, -mcpu=native generates code for the processor at hand, --pgo-train and --pgo build with a profile (Building for Production); -g adds debug information, --target builds for another system (wasm32-wasip1, for WebAssembly), -L and -l link C libraries, and --export keeps every definition visible, for a program that runs others in its own process.

scaly test file [filter]

Runs the tests of the file: every function named test or test_… that takes nothing and answers an int, zero meaning passed; with a filter, only those whose name contains it.

scaly new name [--lib]

Writes a start: a directory with a root file that holds a function, a test for it and a line that prints; with --lib, a package (Starting a package).

scaly install, scaly uninstall

Install the programs a package in a git repository offers, list them, remove one (Installing a Program).

scaly clean

Empties the cache of compiled packages; they are compiled again when a program needs them (The cache).

scaly publish, scaly next

For a package's author: record new versions as published, and begin a package's next version (Versions, and what publishing means).

Building for Production

A program meant to run in production is built in up to three steps, each optional; the toolchain's own programs are built with all three.

--release optimises the whole program as one piece: your code, the standard library and every package, linked and optimised together, with every definition the program does not export kept internal.

scaly build server.scaly --release -o server

-mcpu=native generates code for the processor of the machine that builds — the right choice where the program runs on the machine it was built on, or on identical ones (a container image built on its host). Without it the code runs on every processor of the architecture.

A profile makes the optimiser use what the program actually does. Build it instrumented, run it on a representative load, and build again with the profile it wrote:

scaly build server.scaly --pgo-train -o server-train
  ./server-train                 ; under a typical load; writes default.profraw
  scaly build server.scaly --pgo default.profraw -mcpu=native -o server

The instrumented build needs the profile runtime of clang and llvm-profdata of LLVM 21 (Homebrew's llvm@21 on macOS; llvm-21 and libclang-rt-21-dev on Ubuntu). A profile belongs to the sources it was made from: make it again after they changed — a stale one costs speed, never correctness. The Scaly compiler built this way compiles about 30 percent faster than without its profile.

Installing a Program

A program somebody wrote in Scaly and keeps in a git repository is one command away. dazzle, for one — a DSSSL processor that turns a DocBook book into HTML or a typeset PDF, and the program this documentation is built with:

scaly install github.com/rschleitzer/dazzle dazzle 0.1.0

The three arguments are the repository, the package in it and the package's version. scaly fetches the package and the packages it uses, builds its programs optimised, and puts them into the bin directory of your Scaly installation, which the installer put on your PATH (if it is not there, scaly install says so). A fourth argument names one program where a package offers several. This needs git.

scaly install               ; what has been installed so
  scaly uninstall dazzle      ; remove one of them

The programs of a package has the other side: how a package offers programs.

scalyc

The compiler by itself, with the command line of a C compiler: what scaly build does in one step, scalyc does in the steps a build system asks for.

-o file

The output: an executable, or with -c an object file, with -S LLVM IR.

-c, -S

Compile only, to an object file; emit LLVM IR as text.

-O0 … -O3

The optimisation level; without one the code is not optimised.

-g

Debug information, for a source-level debugger (Using Scaly with Visual Studio Code on macOS and Linux, on Windows Scaly on Windows).

-Lpath, -lname, file.a, file.o

Libraries and objects to link, as a C compiler takes them.

--target triple, -mcpu=cpu

The system the code is for, and the processor (native for the one at hand; the default runs on every processor of the architecture).

--jit, --run function

Compile in memory and run the whole program, or one function of it, in the compiler's own process.

--no-prelude

Compile without the standard library: nothing is visible that the file does not declare.

--task-plan, --loop-census

Reports for the curious: which for loops run on every core and why the others do not, and which while loops could.

scalyc --help lists the rest: the stages of the compiler one by one, and the reports it writes about a program.

scalyls

The language server: an editor starts it and talks to it in the Language Server Protocol, over its standard input and output. It answers with the compiler's own reading of the program — the types inferred, the overload chosen, the region a value lives in — and offers:

  • errors as you type, with the compiler's messages

  • hover: the type of a name, its declaration, and where a value is allocated

  • go to definition, find references, highlight the uses of a name, rename it

  • completion, and the parameters of the call being written

  • an outline of the file, folding, semantic highlighting, formatting

The Scaly extension for Visual Studio Code starts it (Using Scaly with Visual Studio Code on macOS and Linux). Any other editor that speaks the protocol can use it: start scalyls for files ending in .scaly.