Return to home

Introduction

This lesson we will learn more about flow control of a program. In the previous lesson, we built very simple programs that have one path of execution -- there was no variance based on any input. These kinds of programs are pretty uninteresting, as they always do the same thing every time.

But most programs are going to need to make decisions. Think of a computer game. It might load to a menu, but doesn't just complete unless you use controls to move a character around, or perform actions. How does the program know to do something based on your input? This requires using flow control and branching.

Comments

Before we get into the code, I want to introduce comments. Comments are notes that are for you, the programmer. The computer and compiler ignore them completely when building or executing your code.

Another use for comments is "commenting out code", which means you turn code into a comment so it doesn't get run. This is useful for testing or debugging, or simply leaving behind code that is no longer used, but you don't want to delete it.

D has three types of comments:

Doing Math

Computers are really good at doing math! If you wanted the computer to calculate the answer to 1 million math problems, it could do that and get all the answers right, in less than a second.

Before we talk about all the things we can do, we should note how to assign a new value to a variable. In D, this is done with the = operator:

int x = 6; // assignment on declaration
x = 2; // reassignment

Having the computer calculate math is done by using pretty standard math operations. Just like in math, the computer can do addition and subtraction, multiplication and division, and exponentiation. However, some of the symbols and techniques we use in math are hard to type, so we have things that are equivalent in code. The following table describes how to do each operation:

Operation name Mathematical Symbol Equivalent code syntax Example
Addition + + 55 + 127
Subtraction - 150 - x
Multiplication × * val * 5
Division ÷ / int half = value / 2
Exponentiation Superscript, e.g. x² ^^ x ^^ 2

Operator Precedence

D uses standard math operator precedence to perform operations. In math, and in D, the following things take precendence:

  1. Parentheses
  2. Exponentiation
  3. Multiplication and Division
  4. Addition and Subtraction

So the value of 5 + 4 * 3 is 17 both in math and in D. If you want to change the order to get the value 27, you can use parentheses: (5 + 4) * 3.

Branching with if

D has 3 forms of branching. For this lesson we will be focusing only on the if statement. An if statement checks to see if some condition is true or false. If it is true, then the branch code executes. If it is false, the branch code does not execute.

if statements can also be followed by an else statement, which is code to execute when the branch is false. You do not need to include an else statement, it is entirely optional.

if(true) {
    writeln("the condition was true!");
}
else {
    writeln("the condition was false!");
}

Conditions and booleans

Like the int type represents an integer, the bool type represents a boolean. A boolean is a value that can be either true or false. In fact, like 42 is an int, the symobls true and false are typed as bool.

A condition is typically posing a question in the form of a boolean expression. The typical way to get a boolean value is to compare two values. We do this by using the Comparison operators.

Comparision operators are like math, but we use characters that are easy to type when building programs. The following table should help you type the correct operators:

Operation name Mathematical Symbol Equivalent code syntax Example
Less Than < < var < 42
Greater Than > > x > 42
Equal = == word == "hello"
Not Equal != result != "bad value"
Less Than or Equal <= length <= 5
Greater Than or Equal >= units >= 100

One important thing to note here is that comparing two things as equal uses two equal signs, not one. This is because one equal sign is considered to be assignment! The compiler will complain if you try to use one equal sign inside a condition for an if statement

Some examples of if

Let's say we want to print the text "Value is too big!" if the variable dayOfYear is bigger than or equal to 366. The code would look like this:

if(dayOfYear >= 366) {
    writeln("Value is too big!");
}

What if we wanted to check if a command is equal to "exit", and if so, write "Exiting!" and return from the main function?

if(command == "exit") {
    writeln("Exiting!");
    return; // this returns from a function
}

Combining conditions

Boolean logic is the practice of combining different conditions to get one final condition. In code, we have 3 major operations that can accomplish this, and we can use parentheses to clarify which order things should be checked. The three operations are:

Name and effect Code syntax Example
AND: true if both sides are true, otherwise false && age >= 18 && age < 65
OR: false if both sides are false, otherwise true || month == "April" || month == "June" || month == "September" || month == "November"
NOT: the opposite of the current value. true becomes false, false becomes true. ! !(a == b) // same as a != b

Arrays

Sometimes, we want not just one value but a whole list of values. But we don't want to name them all differently! In this case, we use an array. An array is just like any other type, but instead of a single value we get as many values as we want. All the values must be of the same type.

We can declare a variable to have an array type by typing [ ] after the type. It then becomes an array of values of that type. For example, int[ ] x; declares a variable x which is an array of int values.

If you imagine a variable as a box holding a value, then int x = 5; would be a box that contains the value 5:

5

If we declare a new variable int[ ] arr = [1, 2, 3, 4, 5], this declares an array called arr containing 5 boxes, with each one continaing a value from the list. Note the initialization syntax for arrays!

1
2
3
4
5

We can access and change the whole array by using the identifier arr. We can access and change individual values in the array by indexing the array. You index an array using the square brackets, with an index inside the brackets.

A word of caution -- the first index of arrays is always 0! This means that if we wanted to change the 3 value in the array to 100, we would change index 2:

arr[2] = 100; // assign the *third* index to 100
1
2
100
4
5

We can add more values to the end of the list by using the append operation: ~=. If we wanted to add the value 6 to the array, we use the statement arr ~= 6; The array now looks like:

1
2
100
4
5
6

Loops

If we want to do something over and over again, we can use a loop. A loop means that you run a set of code over and over until a stopping condition is reached. The simplest form of loop is called a while loop. It works very similar to an if statement, except that it keeps executing the condition check every time before running the loop code.

int x = 0;
while (x < 100) { // this is checked before every loop
   writeln("x is ", x);
   x = x + 10; // make sure to change x to the next value!
}

The above code will print multiples of 10, starting with 0, and ending with 90. Why not 100? Because 100 is not less than 100! If we also wanted to print 100, we would change the condition to x <= 100.

What happens when you forget to change the value of x? The answer is that the while condition will always be true and therefore will never finish! When this happens, your program will not terminate, and will run forever. This is called an infinite loop. If you need to stop your program, you can use the key-sequence Control-C to stop it.

Foreach loops

If we have an array of data, and we want to loop over all the values in the list, D has a convenient feature for this called a foreach loop. With a foreach loop, you don't have to worry about properly stopping the loop, this is already done for you. You just need to write the code that has to happen for each value in the array.

The best way to show the syntax of foreach is with an example. In this example, we are going to print each value from an array using writeln. Inside the loop, we declare that we want the variable x to contain the value inside the loop:

foreach(x; arr) {
    writeln(x);
}

You can see the syntax inside the parentheses is the name of the variable to use, followed by a semicolon, and then the name of the array to loop over. This kind of loop is one of the most common loops in D for processing data in an array, you will be using it a lot.

Exercise

For this excercise, we are going to do some math, and figure out the answer. In math, the factorial of a number N is the product (multiplication) of all the numbers from N to 1. So the factorial of 5 is 1 × 2 × 3 × 4 × 5.

Let's calculate the factorial for 12. To do this, we will take a variable x and count it up to 12. In each loop, you should change x to the next value, and multiply the variable factorial by x. At the end, we will print out the answer of the factorial for 12.

import std.stdio;

void main()
{
    int factorial = 1;
    int x = 1;
    while(    ) { // write the condition here
        // change factorial and x here
    }
    writeln(factorial);
}

Try working it out for yourself in VSCode, or on run.dlang.io. If you can't figure it out, you can

Return to home

©2023 Steven Schveighoffer