ESC
Type to search...
S
Soli Docs

Control Flow

Conditionals, loops, and flow control statements in Soli.

If/Else Statements

if / else / elsif

Conditional branching statements.

age = 18

# Simple if
if age >= 18
  print("Adult")
end

# If-else
score = 75
if score >= 60
  print("Pass")
else
  print("Fail")
end

# Else-if chain
grade = 85
if grade >= 90
  letter = "A"
elsif grade >= 80
  letter = "B"
elsif grade >= 70
  letter = "C"
elsif grade >= 60
  letter = "D"
else
  letter = "F"
end
print(letter);  # "B"

Unless

unless / end

Runs the body when the condition is falsy — the inverse of if. This is a real statement, not a rewrite of if !cond, so unless a || b keeps that meaning.

unless user.admin?
  halt(403, "Forbidden")
end

# else is allowed; elsif is not
unless cart.empty?
  checkout()
else
  redirect("/cart")
end

# short bodies still format as postfix
return cached unless cached.nil?

Optional then works the same as on if: unless ready then wait() end.

The then Keyword

then

The then keyword is an optional separator between the condition and the body of an if, elsif, or unless statement. It improves readability, especially for single-line conditionals.

# Multi-line with then
if age >= 18 then
  print("Adult")
end

# Single-line with then
if user != null then print("Welcome, " + user.name) end

# Works with elsif too
x = 42
if x > 100 then
  print("big")
elsif x > 10 then
  print("medium")
else
  print("small")
end

# Parentheses and then can be combined
if (score >= 90) then
  grade = "A"
end

# Without then (also valid)
if age >= 18
  print("Adult")
end

Note: then is purely syntactic sugar. Both if condition then ... end and if condition ... end are equivalent. Parentheses around the condition are also optional.

While Loops

while

Repeats while a condition is true.

i = 0
while i < 5
  print("Count: " + str(i))
  i = i + 1
end
# Output: Count: 0, 1, 2, 3, 4

For Loops

for ... in

Iterates over collections or ranges.

# Iterate over array
fruits = ["apple", "banana", "cherry"]
for fruit in fruits
  print(fruit)
end

# Iterate with range
for i in range(0, 5)
  print(i);  # 0, 1, 2, 3, 4
end

# Range with step
for i in range(0, 10, 2)
  print(i);  # 0, 2, 4, 6, 8
end

# Nested loops
for i in range(1, 4)
  for j in range(1, 4)
    print(str(i) + " x " + str(j) + " = " + str(i * j))
  end
end

Postfix Conditionals

expression if / unless

Ruby-style postfix conditionals for concise one-liners.

x = 10
print("big") if x > 5

y = 3
print("small") unless y > 5

status = "active"
print("Welcome!") if status == "active"
print("Account locked") unless status != "banned"

Ternary Operator

condition ? true_value : false_value

Inline conditional expression.

x = 10
size = x > 5 ? "large" : "small"
print(size);  # "large"

# Nested ternary
grade = 85
letter = grade >= 90 ? "A"
      : grade >= 80 ? "B"
      : grade >= 70 ? "C"
      : grade >= 60 ? "D"
      : "F"
print(letter);  # "B"

Exiting and Skipping Iterations

break

Exits the innermost enclosing loop immediately. Works in while and for loops, and supports postfix conditions.

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for n in numbers
  break if n > 7
  print(n)
end
# prints: 1, 2, 3, 4, 5, 6, 7

# Do-while equivalent: infinite `while` + `break`
count = 0
while true
  count = count + 1
  break unless count < 3
end
print(count);  # 3

break propagates out of nested blocks, if branches and try/catch — a finally block still runs before the loop exits. A break inside a lambda or function body does not break an outer loop; it is absorbed at the function boundary.

for path in paths
  try
    contents = File.read(path)
    if contents.blank?
      break        # exits the for loop, not just the if/try
    end
  catch error
    break          # `finally` still runs first
  finally
    print("checked #{path}")
  end
end
next

Skips to the next iteration of the loop.

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
sum = 0
for n in numbers
  if n % 2 == 0
    next
  end
  sum = sum + n
end
print("Sum of odd numbers: " + str(sum));  # 1+3+5+7+9 = 25