Variables and constants
Variables are names for values. In Salam a variable cannot be changed unless you say so, which heads off a whole class of quiet bugs.
Declaring a variable
:= introduces a new name and gives it a value. The type comes from the value, so you do not have to write it: "Maryam" makes a str and 85 makes an int. From then on the type is fixed, and putting text into a number variable later is an error. Names can be several words, such as book price.
const MAX := 100
func main:
name := "Maryam"
mut score := 85
score = score + 10
println name, "scored", score, "out of", MAX
endA variable always starts with a value. There is no way to declare a name now and fill it in later, so you never read a variable that holds leftover garbage.
Changeable variables
A variable declared with := never changes again. If you want to give it a new value later, write mut before the name and then assign with =. The shorthands +=, -= and ++ are there too.
func main:
mut counter := 0
counter = counter + 1
counter += 5
counter++
println "counter:", counter
endSalam is strict about this: if you declare something mut and never change it, or declare a variable and never use it, the program does not compile. The rule catches dead code and typos.
Where a variable lives
A variable exists from the line that declares it to the end of the block it was declared in. A name made inside an if is gone once the if closes, and using it afterwards is an "unknown identifier" error. Keep a variable in the smallest block that needs it.
func main:
subtotal := 140
if subtotal >= 100:
points := subtotal / 20
println "points earned:", points
end
label := "order"
if subtotal > 120:
label := "large order"
println "inside the block:", label
end
println "after the block:", label
endThe second if declares its own label. That is allowed in an inner block, and it hides the outer one until the block ends; the outer label is never touched, as the last line shows. This is called shadowing, and it is easy to misread, so use a new name unless you really mean it. Declaring the same name twice in the same block is an error.
Choosing a value without mut
A common reason to reach for mut is a value that depends on a condition: declare it empty, then set it in each branch of an if. Most of the time the ternary operator does the same job in one line and the variable can stay unchangeable:
func main:
weight_kg := 3
express := true
shipping := weight_kg > 2 ? 15 : 8
speed := express ? "express" : "standard"
println speed, "shipping costs", shipping
endWith more than two cases, a match expression plays the same role. Fewer mut variables means fewer places where a value can change behind your back.
Choosing the type
When you want a type other than the default, convert the value with as. A whole number is int (32 bits) by default and a decimal one is f64.
func main:
age := 17 as i64
height := 1.75
name := "Negar"
student := true
println name, age, height, student
endOlder Salam code wrote the type before the value, as in age: int = 17. That form was removed and is now a parse error that tells you to write age := 17, or age := 17 as i64 when the type matters. The name: Type form lives on only for function parameters and struct fields.
Global variables
Outside any function you can declare global variables with mut and constants with const; every function in the program can reach them. Here a global counts how many times a function has been called:
const RATE := 10
mut calls := 0
func tax(price: int): int:
calls += 1
ret price * RATE / 100
end
func main:
println tax(2000)
println tax(500)
println "calls:", calls
endGlobals go near the top of the file: after the import lines and the constants, and before any type or function. Use them sparingly: a value passed in as a parameter is easier to follow than one that any function might change.
Constants
const declares a value that is fixed when the program is compiled. A constant can be computed from numbers and from other constants, so you can name the parts of a calculation instead of writing a bare 604800. Constants also work inside a function, where they are visible only in that function.
const MINUTE := 60
const HOUR := 60 * MINUTE
const DAY := 24 * HOUR
const APP := "backup"
func main:
const RETRIES := 3
println APP, "keeps files for", 7 * DAY, "seconds"
println "a failed upload is tried", RETRIES, "times"
endThe name of a constant has to be a single word: MAX VALUE is a parse error, so write MAX_VALUE or MAXVALUE. Global variables and ordinary variables may still have names of several words.
There is a difference between := and const that matters once a variable holds several values, such as an array. := fixes the name: it cannot be pointed at a whole new value, but the elements inside can still be changed. const freezes everything, elements included.
const DAYS := ["Sat", "Sun", "Mon", "Tue", "Wed"]
func main:
readings := [21, 23, 91, 24, 22]
readings[2] = 19
println readings
println "reading for", DAYS[2], "fixed to", readings[2]
endHere a wrong reading is corrected in place even though readings is not mut. Writing DAYS[2] = "Fri" instead is an error, because a const is fully immutable.
Naming rules
- Names are made of English or Persian letters, digits and
_, and may not start with a digit. - Upper and lower case are different:
nameandNameare two variables. - Keywords, such as
if,and,toorin, cannot be used as names, and not as one word of a longer name either:max to gois rejected. - A variable cannot share its name with a function in the same file, so a name always means one thing.
- Starting a name with
_silences the unused variable error. The compiler advises against it for dead code, since the code stays in the program; keep it for values you really mean to ignore.
These are the errors you will meet most often while getting used to variables:
| Code | Error | What it means |
|---|---|---|
x := 5 then x = 6 | E013 | cannot reassign immutable variable 'x'; add mut |
mut x := 5, never changed | E069 | declared 'mut' but never mutated; drop the mut |
x := 5, never used | E059 | unused variable 'x' |
x := 5 twice in one block | E001 | redefinition of 'x' |
mut total := 0 then total = "ten" | E002 | cannot assign 'str' to 'i32' |
total := 5 next to func total | E090 | 'total' is already the name of a function in this file |