1. Installing, and the first program

  • chapter 1 of 20
  • 2 min read

Every release on the releases page publishes two toolchains, each with its SHA-256 beside it. They are different compilers, not two downloads of one, so pick by whether you have a JVM.

Without a JVM (linux-x86_64): dawnc is one static executable with the standard library and the C runtime inside it. It compiles through the C backend, so it refuses use java (chapter 11 is the one chapter it cannot follow).

base=https://github.com/dawnop/dawn-lang/releases/latest/download
curl -fsSLO $base/dawnc-linux-x86_64
curl -fsSLO $base/dawnc-linux-x86_64.sha256
sha256sum -c dawnc-linux-x86_64.sha256
chmod +x dawnc-linux-x86_64 && sudo mv dawnc-linux-x86_64 /usr/local/bin/dawnc

With a JVM (JDK 21 or newer, any platform): dawn-selfhost.jar carries the standard library, so the jar on its own is the whole toolchain.

base=https://github.com/dawnop/dawn-lang/releases/latest/download
curl -fsSLO $base/dawn-selfhost.jar
curl -fsSLO $base/dawn-selfhost.jar.sha256
sha256sum -c dawn-selfhost.jar.sha256      # macOS: shasum -a 256 -c

The commands below say dawn. With the static binary that is dawnc; with the jar it is java -jar dawn-selfhost.jar.

dawn run  hello.dawn        # compile and run
dawn test hello.dawn        # run the test blocks in the file
dawn fmt  hello.dawn        # format the file in place

From source, if you have a checkout and JDK 21: ./bin/dawn stands in for dawn. Its first run downloads the seed (the dawn-selfhost.jar of the release pinned by scripts/seed-release.txt, checked against scripts/seed-checksums.txt) and compiles the compiler in selfhost/ with it. There ./bin/dawn build hello.dawn --native -o hello packages the JVM build with GraalVM native-image, which is a different road from dawnc.

The first program. Functions are pure by default; touching IO — printing, here — requires !io on the signature:

pub fn main() -> Unit !io =
  println("Hello, Dawn")
Hello, Dawn

String interpolation is written ${expr}, for a plain variable as much as for any expression (the value interpolated has to be printable). Braces on their own are ordinary characters — without a $ there is no interpolation:

pub fn main() -> Unit !io = {
  let name = "Dawn"
  let year = 2026
  println("${name} was born in ${year}")
}
Dawn was born in 2026

See also: spec.en.md §12.1