Learn · Chapter 1 of 12

Hello, Capa

The smallest possible Capa program, and the one piece of Capa syntax you cannot avoid learning on the way out.

The program

Open your editor and save this as hello.capa:

fun main(stdio: Stdio)
    stdio.println("Hello, Capa")

Three things on three lines. Read it aloud as: "define a function called main, which takes a parameter called stdio of type Stdio; the body calls the println method on stdio with the string "Hello, Capa"".

From a terminal in the same directory:

$ capa --run hello.capa
Hello, Capa

That is your first Capa program running. Everything else in this tutorial builds on this shape.

What just happened

Three things worth knowing about the shape of that file:

  1. Capa is indentation-significant. The body of main is one level indented (four spaces or one tab; mix them and the lexer complains). Like Python. There are no braces.

  2. Capa programs start at a function called main. The compiler looks for it; if you rename or remove it, the program does nothing at run time.

  3. stdio is a parameter, not a global. This is the part of the program that will look unusual if you come from Python or JavaScript. In those languages, print is just there; the standard output stream is ambient authority. In Capa it is a value: the runtime hands a fresh Stdio to main, and only code that holds it can write to standard output.

You do not need to fully internalise capabilities yet. We come back to them properly in chapter 8. For now, the rule is simply: when you want to print, your function needs to receive a Stdio parameter and call println on it.

The two error modes

Try the two simplest mistakes so you see what the compiler does. First, remove the stdio parameter:

fun main()
    stdio.println("Hello, Capa")
$ capa --run hello.capa
hello.capa:2:5: error: undefined name 'stdio'
   2 |     stdio.println("Hello, Capa")
           ^

The compiler refused to run the program. stdio was not a parameter and is not a global, so the name does not exist in scope. This is the capability discipline doing its job: code with no Stdio in scope cannot print.

Second mistake: keep stdio as a parameter but never use it.

fun main(stdio: Stdio)
    let _ = 1 + 1
$ capa --run hello.capa
hello.capa:1:14: error: capability parameter 'stdio' is declared but never used;
                       prefix the name with '_' to silence this check
   1 | fun main(stdio: Stdio)
                  ^

If you ask for a capability, you are committing to use it. A function that takes Stdio but never prints anything is suspicious. If you have a legitimate reason (maybe you are stubbing out a function under construction), prefix the parameter with _: _stdio: Stdio.

A second program

Print two lines. Same shape, two calls:

fun main(stdio: Stdio)
    stdio.println("Hello, Capa")
    stdio.println("Welcome aboard.")

Both lines are in the body of main because they are indented to the same column. Statements are separated by newlines; there is no ;.

Try this. Change the second string to use the apostrophe directly: "Don't be late.". The string is double-quoted so the single quote needs no escape. What about double quotes inside a string? Try writing "She said \"hi\"". Does it work? Why?

Where you are now

You can write a Capa program, save it, and run it. You have seen the compiler reject two kinds of mistake: a missing name and an unused capability. The shape fun main(stdio: Stdio) will be every program you write in this tutorial until chapter 11, when we start importing modules.

The next chapter introduces the building blocks of every program after this one: values, variables, types.