Lesson 1 of 25 · Getting started

Your first program

In this lesson you write and run your first Salam program, learn the handful of commands you will use every day, and get a feel for what Salam code looks like.

Hello, world

Every Salam program starts at func main, the first thing that runs. A block opens with a colon (:) and closes with end, and indenting the lines inside it keeps the code readable. Text goes between double quotes, and println takes its value without parentheses.

hello.salam
func main:
    println "Hello, world!"
end
OutputHello, world!

Running a program

Save your code in a file with a .salam extension, say hello.salam. salam run hello.salam compiles it and runs it straight away. If you want a standalone executable instead, use salam build hello.salam and a native binary appears next to your source. You can also run every example here in the online editor without installing anything.

CommandWhat it does
salam run hello.salamCompiles the program, runs it, and keeps nothing afterwards
salam build hello.salamBuilds a native executable named hello that runs without Salam installed
salam exec hello.salamRuns the program in the interpreter, with no C compiler involved
salam format hello.salamRewrites the file in the standard layout; --check only reports
salam translate fa hello.salamWrites a Persian copy, hello.fa.salam; translate en goes the other way
salam new shopCreates a project folder shop with a salam.salam inside; salam run in that folder runs it
salam versionPrints the version of the compiler
salam updateUpgrades the compiler and its standard library to the newest release; --check only reports whether one is out

Printing output

println prints its values and moves to the next line; print stays on the same line. Separate several values with commas and Salam writes them out with one space between them.

start-print.salam
func main:
    println "Hello", "world"
    print "no "
    print "line break"
    println ""
    println "today it is", 20, "degrees"
end
OutputHello world no line break today it is 20 degrees

Any value can be printed as it is: whole and decimal numbers, true and false, the result of a calculation, even a whole list. Here is a small receipt:

start-values.salam
func main:
    println "Receipt"
    println "notebook", 3, "x", 45
    println "pen", 2, "x", 12
    println "total:", 3 * 45 + 2 * 12
    println "average per item:", (3 * 45 + 2 * 12) / 5.0
    println "paid in full:", true
    println "aisles:", [4, 7]
end
OutputReceipt notebook 3 x 45 pen 2 x 12 total: 159 average per item: 31.8 paid in full: true aisles: [4, 7]

Three rules cover nearly every printing mistake:

  • No parentheses around the values: println "hi", not println("hi").
  • A comma between every two values: println "a", "b". Leaving it out is an error, not a joined string.
  • println always needs a value. For an empty line write println "".

For error messages use printerrln and printerr. They write to standard error, so they stay out of the program's real output and survive being piped elsewhere: with salam run app.salam > out.txt, the normal lines land in the file and the errors still show on screen.

start-stderr.salam
func main:
    println "this line goes to standard output"
    printerrln "this line goes to standard error"
end
Outputthis line goes to standard output this line goes to standard error

Exit codes

When a program ends it hands the operating system a number, its exit code. Zero means success and anything else means something went wrong; scripts and build tools read it to decide whether to carry on. Give main the return type int and the value you ret becomes the exit code. A plain func main: that simply reaches its end exits with 0.

start-exit.salam
func main: int:
    free_mb := 820
    needed_mb := 500
    if free_mb < needed_mb:
        printerrln "not enough space:", free_mb, "MB free,", needed_mb, "MB needed"
        ret 1
    end
    println "enough space, starting the backup"
    ret 0
end
Outputenough space, starting the backup

With 820 MB free the check passes and the program returns 0. Change free_mb to 300 and it prints the message to standard error and exits with 1, which you can see with echo $? right after running it in a Unix shell.

Reading input

input reads one line from the user and gives it back as a string. Like print it takes no parentheses, and it always wants a prompt, which it prints before reading. If you do not want one, write input "". What comes back is always text; when you need a number, convert it with to_int() (or to_float() for decimals):

start-input.salam
func main:
    name := input "Your name: "
    tickets := input "How many tickets? "
    total := tickets.to_int() * 12
    println "Thank you,", name
    println "That comes to", total, "dollars"
end

If the user types something that is not a number, to_int() gives 0 rather than stopping the program, so check the value before trusting it. This example waits for a person at the keyboard, which is why it shows no output here.

Comments

Anything after // to the end of the line, and anything between /* and */, is a comment and is not run.

start-comments.salam
// this is a single line comment and is not run

/*
A block comment:
anything between these two markers is ignored.
*/

func main:
    println "comments never show up in the output" // this is a comment too
end
Outputcomments never show up in the output

Block comments nest: a /* ... */ inside another one is fine, so you can wrap a stretch of code that already contains a block comment to switch it off for a moment.

One line blocks

When the body of a block is short, you can put the whole thing on one line:

start-oneline.salam
func main: println "a one line program" end
Outputa one line program

The shape of a program

A real program is more than main. A source file is read from the top, in this order: import lines for libraries, then constants, then global variables, then your own types, then functions. Functions can call each other in any order, so main is free to sit at the top and use helpers that are written further down.

start-shape.salam
import str

const SHOP := "Salam Books"

func main:
    println SHOP
    println divider()
    println line("The Little Prince", 2)
    println line("Dune", 1)
end

func divider(): str:
    ret str.Repeat("-", 20)
end

func line(title: str, copies: int): str:
    ret title + " x " + copies
end
OutputSalam Books -------------------- The Little Prince x 2 Dune x 1

import str brings in the string library, and str.Repeat is one of its functions; the packages lesson covers libraries properly. A constant below a function, or an import below a constant, is a compile error that tells you where to move it.

When the compiler says no

Salam checks a lot before it runs anything, and it points at the exact line and column with a message that says what to do. These are the ones a beginner meets first:

You wroteThe compiler says
println("hi")print arguments must not be wrapped in parentheses; remove them
println on its ownprint needs a value: write 'println ""' for an empty line
println "a" "b"expected ',' between the values to print
x := 5, and x is never usedE059: unused variable 'x'
a && b'&&' is not a Salam operator; write 'and'

Read the first message first: one mistake can cause a few more errors below it, and those usually go away once the first is fixed. The compiler rules lesson explains the stricter checks and why they help.

Salam is bilingual: every program on this site can also be written with Persian words. The keyword lesson has the full table.