Control structures - if, try, for, while, until

Control structures control the flow of execution by providing mechanism for branching and repeating execution of code. Imba has several different control structures.

  • if blocks control branching
  • try blocks handle exceptions
  • loops (for, while, until) allow repetitive execution of code blocks

Cheats

  • Imba has the if, try, while, until and for blocks.
  • All blocks are expressions which can be assigned and passed around.
  • There are no parentheses around conditions.
  • There is no punctuation in blocks (e.g., if x).
  • if block can have else if and else branches.
  • for, white, until can be passed and assigned as arrays.
  • for, white, until can break and continue.
  • for x in arr or for x, idx in arr to loop over arrays.
  • for key of obj or for key, val of obj to loop over object properties.
  • There is no for i; i < j; i++ version of for loop in Imba.
  • catch is optional in try block.

The if block

Sometimes we want to do different things depending on some condition. For instance, 'if user is logged in, show them the profile page, and otherwise take them to the log in page.'

Just like the name suggests, the if blocks are only evaluated if some condition is met. The condition can be any valid Imba expression, including any of the control blocks found in this section (yes, if block itself, too!).

For example:

1
2
3
4
var lives = 0

if lives is 0
    'You are dead'

We can also specify what happens in the other case:

1
2
3
4
5
6
7
var lives = 3

if lives is 0
    'You are dead'
else
    lives -= 1
    "You have {lives} more lives"

The if block is not restricted to just if and else branches. One or more additional conditions can be specified as else if branches. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var lives = 3

if lives is 0
    'You are dead'
else if lives is 1
    lives -= 1
    'You are mine next time!'
else
    lives -= 1
    "You have {lives} more lives".

If blocks can be assigned to variables.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var lives = 3

var x = if lives is 0
    'You are dead'
else
    lives -= 1
    "You have {lives} more lives"

x
# "You have 2 more lives"

Ternary expression

In some cases, we can write the if block as a ternary expression to save space. Ternary expression is not technically a control structure, but we will mention it here because we don't have a better things to do anyway.

1
2
var lives = 3
var isDead = if lives is 0 then yes else no

The else if branches cannot be used in ternary expressions.

The try block

Perfectly valid code will sometimes throw exceptions. Exceptions are objects generated by some error condition or thrown by some code. Exception objects will propagate through the application from the point where it was thrown, then back up through the path that lead to the point. If it is not caught somewhere on the path, it will eventually reach the JavaScript engine itself, and be treated as an 'uncaught' exception. (This is usually going to show up as a traceback in the developer console or in the terminal.)

1
2
3
4
5
6
7
def foogGun
    throw Error 'bug!'

try
    footGun
catch e
    console.log "That was close! Let's do it again!"

The e variable in the catch branch is the error object that was thrown by the footGun method.

Note that the catch branch is optional. If we simply wish to suppress an exception without doing anything, we can completely omit it.

1
2
3
try
    fooGun
# Look, mom, no catch!

Like if blocks, the try block can be assigned

1
2
3
4
var afermath = try
    footGun
catch e
    'Feeling exceptionally good!'

The while loop

The while loop is the simplest control structure for repeating blocks of code. It repeats the block while some condition is met, hence the name.

1
2
3
4
var bullets = 1000

white bullets > 0
    bullets--

Other than letting the while loop run until the condition no longer applies, we can also end it prematurely by using the break or return statements.

1
2
3
4
5
6
7
8
var count = 0

while yes  # yes is always yes, so this will loop indefinitely
    count++
    break

count
# 1

The return statement can only be used inside methods or do blocks as it doesn't really terminate the while loop, but returns from the method or do block completely.

While looping inside a while loop, we can use continue to skip the rest of the block. It's basically like jumping back to the top of the block.

1
2
3
4
5
6
7
var evenNumbers = []
var i = 0

while i++ < 200
    if i % 2
        continue
    evenNumbers.push i

The until loop

The until loop is similar to the while loop, with a reverse condition: it will stop only once the condition is met. It is just a shorter way to say while not condition.

1
2
3
4
var baloons = [1, 2, 3, 4, 5]

until baloons:length is 0
    baloons.pop

We can use break, return and continue inside until just like in the while loops.

The for loop

Whereas the while and until loops are more generic, for loop is used specifically for iterating over array members and object properties.

There are two variants of for loops:

  • for ... in for arrays, strings, and array-like objects.
  • for ... of for object properties.

The for ... in loop is used like this.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var colorIndex = {
    R: '#ff0000'
    G: '#00ff00'
    B: '#0000ff'
    C: '#00ffff'
    M: '#ff00ff'
    Y: '#ffff00'
}

var colorSequence = ['R', 'M', 'R', 'G', 'B', 'C', 'M']
var colors = []

for colorKey in colorSequence
    colors.push colorIndex[colorKey]

For loops are actually arrays, and they can be assigned and passed. In the previous example we kept pushing into the colors array. This can be written simply like so:

1
2
var colors = for colorKey in colorSequence
    colorIndex[colorKey]

In for loops, we can also access the the indices of members we are iterating over.

1
2
3
var colors = for colorKey, index in colorSequence
    intensity: (index + 1) * 100
    color: colorIndex[colorKey]

The for ... of loop is used for objects. In it's simpler form, for ... of iterates over the keys.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var colorIndex = {
    R: '#ff0000'
    G: '#00ff00'
    B: '#0000ff'
    C: '#00ffff'
    M: '#ff00ff'
    Y: '#ffff00'
}

var allColors = for key of colorIndex
    key

We can also use for ... of to iterate over both keys and values.

1
2
3
4
var reverseIndex = {}

for key, val of colorIndex
    reverseIndex[val] = key

Just like the while loop, we can use break, return and continue to terminate the loop or skip iterations.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
var players = [
    {name: 'OP', dmg: 400, hp: 100}
    {name: 'Nuclear', dmg: 300, hp: 200}
    {name: 'Voe', dmg: 280, hp: 210}
    {name: 'Polygon', dmg: 220, hp: 180}
    {name: 'Glitter', dmg: 440, hp: 120}
    {name: 'Vanilla J', dmg: 300, hp: 50}
]

var strongPlayers = for player in players
    if player:dmg >= 300
        player:name
    else
        continue

strongPlayers
# ['OP', 'Nuclear', 'Glitter', 'Vanilla J']