If-Else & Loops

ReScript supports if, else, ternary expressions (a ? b : c), numeric for loops, for of, and while. Use break to exit a loop early and continue to skip to its next iteration.

The switch pattern supports a default case. Read more about pattern-matching & destructuring.

If-Else & Ternary

ReScript's if is an expression; it evaluates to its body's content:

ReScriptJS Output
let message = if isMorning {
  "Good morning!"
} else {
  "Hello!"
}

Note: an if-else expression without the final else branch implicitly gives () (aka the unit type). So this:

ReScriptJS Output
if showMenu {
  displayMenu()
}

is basically the same as:

ReScriptJS Output
if showMenu {
  displayMenu()
} else {
  ()
}

Here's another way to look at it. This is clearly wrong:

RES
let result = if showMenu { 1 + 2 }

It'll give a type error, saying basically that the implicit else branch has the type unit while the if branch has type int. Intuitively, this makes sense: what would result's value be, if showMenu was false?

We also have ternary sugar, but we encourage you to prefer if-else when possible.

ReScriptJS Output
let message = isMorning ? "Good morning!" : "Hello!"

if-else and ternary are often replaced by pattern matching, which handles a wide range of conditional logic more expressively.

For Loops

Numeric for loops iterate over integers from a starting value up to (and including) the ending value. The loop variable is local to the loop body.

ReScriptJS Output
for i in startValueInclusive to endValueInclusive {
  Console.log(i)
}
ReScriptJS Output
// prints: 1 2 3, one per line
for x in 1 to 3 {
  Console.log(x)
}

You can make the for loop count in the opposite direction by using downto.

ReScriptJS Output
for i in startValueInclusive downto endValueInclusive {
  Console.log(i)
}
ReScriptJS Output
// prints: 3 2 1, one per line
for x in 3 downto 1 {
  Console.log(x)
}

For Of Loops

Use for of to visit each value in an array or an iterable<'a>, without managing an index:

ReScriptJS Output
let names = ["Ada", "Grace", "Margaret"]

for name of names {
  Console.log(name)
}

The loop binding must be a variable name or _. To destructure a value, do so inside the loop body:

ReScriptJS Output
for entry of [("Ada", 36), ("Grace", 85)] {
  let (name, age) = entry
  Console.log(`${name}: ${age->Int.toString}`)
}

For asynchronous iteration, see For Await Of.

Break & Continue

break exits the nearest enclosing loop immediately. continue skips the rest of the current iteration and starts the next one. Both work in numeric for, for of, for await of, and while loops.

ReScriptJS Output
// Prints 1 and 3
for number in 1 to 5 {
  if number == 2 {
    continue
  }
  if number == 4 {
    break
  }
  Console.log(number)
}

In a numeric for loop, continue still advances the loop variable. In a while loop, it rechecks the condition, so make sure any necessary updates happen before continue.

You can also use break and continue inside a switch within a loop: they target the loop, not the switch. They cannot be used outside a loop or from a nested function to control an outer loop.

break and continue are reserved keywords, so they cannot be used as ordinary variable names.

While Loops

While loops execute their body while the condition is true. The condition is checked before each iteration, so the body may never run.

ReScriptJS Output
while testCondition {
  Console.log("Still running")
}

Exiting Early

Use break when the stopping condition is discovered inside the loop. There is no need for a separate mutable stop flag:

ReScriptJS Output
while true {
  if Math.random() > 0.3 {
    break
  }
  Console.log("Still running")
}