Control flow

Deciding and repeating. If you come from C, C++, Java or C#, all of this will look familiar down to the punctuation.

site/snippets/control.vx
i32 main() {
    // Condicional. Las llaves no son opcionales.
    i64 nota = 7;
    if (nota >= 9) {
        println("sobresaliente");
    } else if (nota >= 5) {
        println("aprobado");
    } else {
        println("suspenso");
    }

    // while: comprueba antes de entrar.
    i64 i = 0;
    while (i < 3) {
        println("while ${i}");
        i = i + 1;
    }

    // do-while: ejecuta el cuerpo y comprueba despues, asi que siempre corre
    // al menos una vez.
    i64 intentos = 0;
    do {
        intentos = intentos + 1;
    } while (intentos < 5);
    println("intentos = ${intentos}");

    // for clasico: inicializacion, condicion y paso, en la misma linea.
    for (i64 k = 0; k < 3; k++) {
        println("for ${k}");
    }

    // foreach sobre un array: no hay indice de por medio.
    i64[4] datos = {10, 20, 30, 40};
    i64 total = 0;
    for (i64 v : datos) {
        total = total + v;
    }
    println("suma = ${total}");

    // break sale del bucle; continue salta a la siguiente vuelta.
    for (i64 m = 0; m < 10; m++) {
        if (m % 2 == 0) { continue; }
        if (m > 6) { break; }
        println("impar ${m}");
    }

    // El ternario elige entre dos valores sin escribir un if.  Se calcula
    // fuera de la cadena: dentro de ${...} los dos puntos se confunden con el
    // separador del especificador de formato.
    i64 a = 9;
    i64 b = 4;
    i64 mayor = a > b ? a : b;
    println("mayor = ${mayor}");

    // match compara el valor contra varias formas. El guion bajo recoge todo
    // lo que no haya casado antes.
    i64 codigo = 3;
    match codigo {
        case 1 => println("aceptado");
        case 2 => println("pendiente");
        case _ => {
            println("desconocido:");
            println("  codigo = ${codigo}");
        }
    }

    return 0;
}
aprobado
while 0
while 1
while 2
intentos = 5
for 0
for 1
for 2
suma = 100
impar 1
impar 3
impar 5
mayor = 9
desconocido:
  codigo = 3

Conditionals

if, else if and else, with the condition in parentheses.

Braces are optional when the body is a single statement, as in C:

if (n > 0) println("positive");

Even so, put them in anyway. It is the habit that avoids the family of bugs that shows up when someone adds a second line to a braceless if and that line ends up running no matter what.

A number works as a condition too: zero is false, anything else is true. if (n) compiles and does what you expect. Writing if (n != 0) says the same thing more explicitly, and that is what this path uses.

while and do-while

while checks the condition before entering, so it may not run at all.

do { ... } while (cond); runs the body and checks afterwards, so it always runs at least once. That is what you want when the body itself produces the value you are going to test: reading input, attempting a connection, processing a block.

Note the semicolon at the end of the do-while: it is part of the syntax.

for

The classic for, with its three parts separated by semicolons:

for (i64 k = 0; k < 3; k++) { ... }

Initialisation, condition and step. The variable declared there only exists inside the loop.

Walking an array

When all you want is to visit every element, the index is in the way:

i64[4] datos = {10, 20, 30, 40};
for (i64 v : datos) {
    total = total + v;
}

Read it as "for each v of type i64 in datos". v is a copy of the element, not the element, so changing it does not change the array.

Arrays get their own chapter later; knowing how to walk them is enough here.

break and continue

break leaves the loop. continue abandons the current pass and jumps to the next. Both act on the innermost loop that contains them.

for (i64 m = 0; m < 10; m++) {
    if (m % 2 == 0) { continue; }   // evens are not interesting
    if (m > 6) { break; }           // from 7 on, we are done
    println("impar ${m}");
}

goto

The language has goto and labels, for the same job as in C: leaving several nested loops at once, or jumping to a shared cleanup block.

Jumping backwards does not work today. A jump to an earlier label loses whatever was written into variables since that label, so the loop never makes progress and the program spins. Use while or for until this is fixed.

The ternary

When all you want is to pick between two values, if is too much:

i64 mayor = a > b ? a : b;

Read it as "if a > b then a, otherwise b".

Do not put it inside a string. "${a > b ? a : b}" does not compile: the colon of the ternary is mistaken for the separator of the ${expr:fmt} format specifier. Work the value out first, then interpolate it.

match

match compares a value against several possible shapes. If you come from C or Java, it takes the place of switch, which in Vesta does not exist.

match codigo {
    case 1 => println("aceptado");
    case 2 => println("pendiente");
    case _ => {
        println("desconocido:");
        println("  codigo = ${codigo}");
    }
}

Each case takes => followed by a statement or a braced block. The underscore _ catches everything that did not match earlier, playing the role of default.

Two differences from C's switch you will appreciate: cases do not fall through, so there is no break to write at the end of each one, and therefore no bug from forgetting it.

Here match is comparing numbers, and for that you would hardly need a construct of its own. Its real use arrives with enum types, where besides matching the shape it pulls out the data carried inside. That is a couple of chapters away.

What comes next

You can compute, decide and repeat. Next comes giving all of that a name: functions.