Conditions
Conditions are how a program decides, from its data, which way to go. Salam keeps them strict: a condition is always a real bool, and the compiler points out branches that could never run.
if, else if, else
The body of an if runs only when its condition holds. Test further conditions with else if, and cover everything that is left with else. The conditions are tried from the top, and only the first one that holds runs, so put the narrowest test first.
func grade(score: int): str:
if score >= 90:
ret "excellent"
else if score >= 70:
ret "good"
else:
ret "needs more work"
end
end
func main:
println grade(95)
println grade(72)
println grade(40)
endA score of 95 is also at least 70, but the program prints only excellent: once a branch has run, the rest are skipped.
Short conditions, and joining them
A short condition fits on one line, with end at the end of the line. Join several conditions with and and or.
func main:
number := 7
if number % 2 == 0: println "even" else: println "odd" end
if number > 0 and number < 10:
println "a positive single digit number"
end
endComparison words
Every comparison operator also has a word: eq for ==, neq for !=, lt and gt for < and >, and lte and gte for <= and >=. Use whichever reads better; they mean exactly the same. The example also shows the short form of else if: else followed directly by a condition.
func ticket(age: int): int:
if age lt 4:
ret 0
else age lte 12:
ret 40
else age gte 65:
ret 50
else:
ret 90
end
end
func main:
println ticket(2), ticket(9), ticket(30), ticket(70)
seats := 12
sold := 12
if sold eq seats: println "sold out" end
if sold neq seats: println "seats left" end
endand, or and not
and and or stop as soon as the answer is known. If the left side of and is false, the right side is never evaluated, and the same goes for or when the left side is true. That makes the left side a guard for the right: test that a count is not zero before dividing by it, or that an index is in range before reading the array.
func average(total: int, count: int): int:
if count != 0 and total / count > 0:
ret total / count
end
ret 0
end
func main:
println average(270, 3), average(0, 0)
scores := [12, 18, 7]
i := 5
if i < len(scores) and scores[i] > 10:
println "a high score"
else:
println "no score at", i
end
logged_in := true
banned := false
if logged_in and not banned:
println "welcome back"
end
stock := 3
if not (stock > 5):
println "time to reorder"
end
endnot binds tighter than a comparison. not stock > 5 would mean (not stock) > 5, which is an error because stock is not a bool. Write not (stock > 5), or simply stock <= 5. There is no &&, || or ! in Salam; the compiler names the word to write instead.
Choosing a value
A variable declared inside a branch disappears at that branch's end. When each branch decides a value, declare the variable with mut before the if and assign it in the branches. For a choice between just two values, the ternary operator condition ? a : b is shorter, and both sides must have the same type.
func main:
weight := 3
express := true
mut cost := 0
if weight <= 1:
cost = 30
else weight <= 5:
cost = 55
else:
cost = 90
end
if express:
cost += 25
end
println "shipping:", cost
label := weight > 2 ? "heavy" : "light"
println label
endReturning early
Deeply nested ifs are hard to read. Inside a function, check for each problem in turn and ret as soon as one is found. What is left at the bottom is the normal case, with no nesting at all.
func check_order(qty: int, stock: int, paid: bool): str:
if qty <= 0:
ret "the quantity must be at least 1"
end
if qty > stock:
ret "only " + stock + " left in stock"
end
if not paid:
ret "waiting for payment"
end
ret "order accepted"
end
func main:
println check_order(0, 10, true)
println check_order(12, 10, true)
println check_order(2, 10, false)
println check_order(2, 10, true)
endComparing floats
Most decimal fractions cannot be stored exactly in binary, so a little rounding error creeps into arithmetic. 0.1 + 0.2 comes out as 0.30000000000000004, and == against 0.3 is false. Compare floats by asking whether their difference is small enough. For money, keep amounts in whole units (cents, rials) as integers, or use the decimal package.
import math
func main:
paid := 0.1 + 0.2
price := 0.3
println paid
if paid == price:
println "equal"
else:
println "not equal"
end
if math.Abs(paid - price) < 0.000001:
println "close enough"
end
endThe rules a condition follows
- A condition has to be a
bool.if number:is an error; writeif number != 0:. if x = 3:is an error that tells you to write==(oreq).if x == 1 or 2:is an error too, because2is not abool. Writex == 1 or x == 2.- A condition that is always true, or always false, such as
if 2 > 1:, is rejected, because one of the branches would never run. - No branch may be empty. Instead of an empty branch, invert the condition with
not. - A variable declared inside a branch cannot be used after the branch's
end.
When one value is compared against many possible cases, a long else if chain gets tiresome. The next lessons cover loops, and then match and switch, which are made for exactly that.