Learn menu

Your First Program

Time to write some Turf. You'll make a program that says hello, find out what every part of it means, and see what happens when something goes wrong.

By the end of this page you will

  • Write a Turf program in a file and run it with turf run.
  • Explain what every line of hello.tr does.
  • Read an error from the compiler and fix it.
  • Make a project with turf new and run a test with turf test.

Make a file

A Turf program lives in a plain text file whose name ends in .tr. That ending tells everyone, including the compiler, that the file holds Turf.

  1. Make a folder for your code

    Somewhere easy to find, such as your home folder. Call it turf-practice.

  2. Make a new file in it called hello.tr

    Use your text editor’s New File and Save As. Check the name ends in .tr and not .tr.txt: some editors add .txt without asking.

  3. Open a terminal in that folder

    In the terminal, cd means “change directory”, which means go into a folder. Type cd turf-practice and press Enter.

Terminal
mkdir turf-practicecd turf-practice

The two commands above do steps 1 and 3 from the terminal: mkdir makes a folder, and cd goes into it.

Type the program

Type this into hello.tr, or copy it with the button, and save the file:

hello.tr
fn main(): int {    printline("Hello, world!");    return 0;}

Be careful to copy every symbol exactly: the brackets ( ), the curly braces { }, the quote marks " " and the semicolons ;. To a compiler, every one of them matters.

Run it

Back in the terminal, type:

Terminal
turf run hello.tr

and you should see this:

Terminal
$ turf run hello.tr
Compiled to /tmp/turf-run-228119781/hello.o
Successfully compiled to /tmp/turf-run-228119781/hello
Hello, world!

You just wrote and ran a program!

The first two lines are turf telling you it compiled your program and where it put it. The last line is your program running: that’s your Hello, world!.

What each line means

Here is hello.tr again, taken apart one line at a time:

hello.trline by line
  1. 1fn main(): int {

    fn starts a function: a named list of instructions. This one is called main, and that name is special: main is where every Turf program starts. The empty () means it needs nothing to get going, : int says it gives back a whole number when it finishes, and { opens its body.

  2. 2    printline("Hello, world!");

    printline prints some text, then moves to a new line. The text goes between double quotes. The ; at the end finishes the instruction, like a full stop finishes a sentence.

  3. 3    return 0;

    return ends the function and hands back a value. For main, the number goes back to the computer, and 0 means “everything went well”.

  4. 4}

    The closing } ends the body of main. Every { needs a matching }.

Make it your own

Programs get interesting when you change them. Here’s hello.tr with a variable: a name that holds a value, so you can use it later. immut name = "Turf"; makes a variable called name that holds the text "Turf" (immut means it can’t be changed later; Language Basics explains). Then + joins pieces of text together:

hello.tr
fn main(): int {    immut name = "Turf";    printline("Hello, " + name + "!");    return 0;}

$ turf run hello.tr

Hello, Turf!

Each printline prints its own line, so several of them print several lines, top to bottom, in order:

lines.tr
fn main(): int {    printline("Roses are red,");    printline("violets are blue,");    printline("this program runs,");    printline("and so can you.");    return 0;}

$ turf run lines.tr

Roses are red, violets are blue, this program runs, and so can you.

When things go wrong

Everybody makes mistakes when they program, including people who’ve done it for years. What matters is finding them quickly, and that’s where the compiler helps. Let’s make a mistake on purpose.

A misspelled name

This program spells name as nmae on line 3. To see what’s wrong without running anything, use turf check: it reads the program and reports every problem it finds.

oops.tr
fn main(): int {    immut name = "Turf";    printline("Hello, " + nmae + "!");    return 0;}
Terminal
$ turf check oops.tr
oops.tr (1 error)

── error at line 3, col 27 [E040 · undeclared variable]

  I can't find anything named 'nmae'.

  Hint: It may be from the current file: 'name'

  3 │     printline("Hello, " + nmae + "!");
    │                           ^~~~ Here!

  Run `turf --explain E040` for more details.

That’s a lot of text, but every part has a job. From top to bottom:

  1. Which file, and how many problems

    oops.tr (1 error): the file and the number of errors in it.

  2. Where, and what kind

    line 3, col 27 is the spot: line 3, 27 characters along. E040 is the error’s code, and undeclared variable is the kind of error.

  3. The message

    What’s wrong, in plain words: there is nothing called nmae.

  4. The hint

    A suggestion for fixing it. Here the compiler noticed that name looks very similar, so you probably meant that.

  5. The picture

    Your line of code, with ^~~~ Here! underlining the exact problem.

  6. Where to learn more

    A command that explains this kind of error in detail.

Fix the spelling, run turf check oops.tr again, and it prints nothing at all. When turf check is silent, there are no errors.

Asking turf to explain

Every error code has a longer explanation, with examples. Ask for it with turf explain and the code:

Terminal
$ turf explain E040
E040  ReferenceError (UNDECLARED_VARIABLE)

I can't find anything with that name

Turf looked everywhere it knows to look -- the current block, any block around it, the whole file -- and couldn't find anything called by that name. No variable, no struct, no enum, nothing. This is the most common error you'll hit while learning, and it's almost always one of two very fixable things.

The first is a plain typo:

    mut count: int = 0;
    count = coutn + 1;   // typo! should be "count"
...

A missing semicolon

Here’s another very common mistake: a ; left off the end of line 2.

semi.tr
fn main(): int {    printline("Hello, world!")    return 0;}
Terminal
$ turf check semi.tr
semi.tr (1 error)

── error at line 3, col 5 [E102 · syntax error]

  Expected ';' after statement.

  3 │     return 0;
    │     ^~~~~~ Here!

  Run `turf --explain E102` for more details.

Notice that the error points at line 3, not line 2. That’s because the compiler only knows the ; is missing when it reaches return and finds something it didn’t expect. When an error points at the start of a line, look at the end of the line before it too.

A program you can keep

turf run throws its program away when it’s done. To keep a program, so you can run it again any time without Turf, compile it with turf and a file name. -o hello names the program it makes:

Terminal
$ turf hello.tr -o hello
Compiled to hello.o
Successfully compiled to hello
$ ./hello
Hello, world!

Now there’s a program called hello in your folder, and ./hello runs it. The ./ means “the one in this folder”. Along the way the compiler also made hello.o, a halfway step called an object file; you can ignore it.

Your first project

One file is fine for practice. Bigger programs are split over many files, and they have tests and settings. For that, Turf has projects. turf new makes one for you, ready to run:

Terminal
$ turf new hello
Created program package 'hello' in hello/
  hello/turf.toml
  hello/src/main.tr
  hello/README.md
  hello/.vscode/extensions.json
  hello/.gitignore
$ cd hello
$ turf run
Compiled to build/hello.o
Successfully compiled to build/hello
Hello, TurfLang! This is hello.

Inside a project you just type turf run, without a file name: turf knows where to start. Here’s what it made:

hello/
  • turf.tomlthe manifest: the project’s name, version and settings
  • src/your code lives here
  • main.trwhere the program starts: what turf run runs
  • README.mda short page about the project, with everyday commands
  • .vscode/recommends the Turf extension to VS Code
  • .gitignoretells git not to save the build/ folder
  • build/appears when you build: the finished program goes here

turf.toml is short. TOML is a simple format for settings: names on the left, values on the right.

[package]
name = "hello"
version = "0.1.0"
turf = "2.0"

[dependencies]

turf = "2.0" says this project needs Turf 2.0 or newer. [dependencies] is where other people’s code you use will be listed; it’s empty for now.

And this is src/main.tr:

src/main.tr
// src/main.tr: this package's entry point. `turf run` builds and runs it.import io;fn main(): int {    io::printline("Hello, TurfLang! This is hello.");    return 0;}

Two things are new here:

  • The first line starts with //, so it’s a comment: a note for people. The compiler skips everything from // to the end of the line.
  • import io; brings in the standard library’s io module, where printing lives, and io::printline means “the printline from io”. You didn’t need this in hello.tr because the most common modules, io among them, are always available. Writing io:: just makes it clear where printline comes from.

Build without running

turf build compiles the project without running it. The program is saved as build/hello:

Terminal
$ turf build
Compiled to build/hello.o
Successfully compiled to build/hello

Your first test

A test is a small program that checks your code does what you expect. In a project, tests live in a folder called tests/. Make that folder, and put this in tests/basic.tr:

tests/basic.tr
import test;fn main(): int {    test::assert(1 + 1 == 2, "arithmetic still works");    return 0;}

test::assert checks that something is true. Here it checks that 1 + 1 == 2; == means “is equal to”. If it weren’t true, the test would fail and print the message. Now run every test in the project:

Terminal
$ turf test
Running Turf Test Suites...

[tests] basic.tr ... PASS

=== Test Summary ===
Total Tests: 1
Passed:      1
Failed:      0

All tests passed successfully!

Every file in tests/ runs as its own program, and a test passes when it finishes with 0.

A failing test looks like this. The details at the bottom name the file and the line (basic.tr:4), followed by your message:

Terminal
$ turf test
Running Turf Test Suites...

[tests] basic.tr ... RUNTIME FAILED (Exit code 134)

=== Test Summary ===
Total Tests: 1
Passed:      0
Failed:      1

Failed Tests Details:

--- tests/basic.tr (Runtime Error exit 134):
basic.tr:4: arithmetic still works
 ---

What you learned

  • A Turf program is a .tr file, and it starts at fn main().
  • turf run file.tr compiles a program and runs it; turf file.tr -o name makes a program you can keep.
  • turf check finds mistakes, and turf explain explains an error code.
  • turf new makes a project; turf run, turf build and turf test work inside it.

Next, you’ll learn the building blocks every program is made of: values, variables, maths, choices and loops.

Esc

Type to search.