Skip to content
Image with logo, providing a link to the home page
  • United Stated of America flag, representing the option for the English language.
  • Bandeira do Brasil, simbolizando a opção pelo idioma Português do Brasil.

Learn Programming: Conditional Structures

Examples of conditional structures in Python, Lua, GDScript and JavaScript.

Image credits: Image created by the author using the program Spectacle.

Requirements

In the introduction to development environments, I have mentioned Python, Lua and JavaScript as good choices of programming languages for beginners. Later, I have commented about GDScript as an option for people who want to program digital games or simulations. For the introductory programming activities, you will need, at least, a development environment configured for one of the previous languages.

If you wish to try programming without configuring an environment, you can use of the online editors that I have created:

However, they do not provide all features offered by interpreters for the languages. Thus, sooner or later, you will need to set up a development environment. If you need to configure one, you can refer to the following resources.

Thus, if you have an Integrated Development Environment (IDE), or a combination of text editor and an interpreter, you are ready to start. The following example assumes that you know how to run code in your chosen language, as presented in the configuration pages.

If you want to use another language, the introduction provides links for configure development environments for the C, C++, Java, LISP, Prolog, and SQL (with SQLite) languages. In many languages, it suffices to follow the models from the experimentation section to modify syntax, commands and functions from the code blocks. C and C++ are exceptions, for they require pointers access the memory.

Control Flow

Programs start in an entry point and finish at an exit point. Every program written hitherto start at the entry point and end at a very same exit point, executing all the instructions defined in between in the defined order.

In complex programs, this does not always happen. In reality, it is very common to choose one among two or mode options to execute the code block that is more appropriate to the current values of the program. In other words, the state of a program can affect how it runs.

The term branch refers to the possibility of changing the sequence of instructions through a jump to a code line that is potentially different from the next one. Jumps can be unconditional (for instance, using go to) or conditional.

An unconditional jump always happens; a conditional jump depends on a conditional defined in the source code. With combinations of variables and arithmetic, relational and logic operations, it is possible to create alternative flows to run a program.

Hereafter, it is convenient to start imagining the source code of a program as composed by blocks. As an edification as rooms (living rooms, kitchens, halls...), programs have blocks of source code.

To move between a starting point to an ending point in a house, one moves by sequence of rooms. One does not always visit every room of a house; she/he visits only the ones that are necessary to reach the destiny.

Programs work similarly. According to the provided data, they can run (or not) different parts of the defined source code. The term control flow refers to the order in which the machine runs the instructions of a program.

Structured Programming

Programs, like buildings, have structures.

In programming, a traditional model (paradigm) of programming is called structured programming. A result of the structured program theorem is the possibility of creating any program by means of three patterns: sequence, selection and iteration.

Up to now, every program was built be means of sequences of instructions. Sequences are run in the order that they are defined. They can be instructions (at a lower level) or subprograms (at a higher level). Sequences as subprograms mean that is it possible to build sequences composed of selections and iterations.

Selection allow to choose one between two alternative paths to follow, based in a logic value for the decision. In other words, conditions can be created with relation and/or logic operators to define the next instruction of a program. Depending on the value, the next instruction to run can be defined by a jump, instead of being the next line in the source code.

Iterations are repetitions of existing instructions. The iteration combines selections with jumps to a block of instructions that can be repeated zero or more times (or one or more times, depending on how it is structured). The combination allows the program to repeat the very same sequence considering a condition. While the condition is true, the code is repeated. When the condition becomes false, the program jumps to a different sequence of instructions. If the condition does never become false, the program repeats itself infinitely (something that will be called infinite loop after the introduction of repetition structures).

In modern programming languages, selections are abstracted by conditional structures (or structures of conditions). Iterations are abstracted by repetition structures, also called loops. It is also possible to perform iterations by means of recursive subroutines.

As iterations depends on selections, it is worth considering conditional structures first.

Conditional Structures

In modern programming languages, selection are commonly implemented using conditional structures. The structure abstract the jump, enabling the programming to think in high level when she/he programs.

Although there exists different conditional structures, two are most common in modern programming languages:

  1. If, Then, Else, hereafter called if;
  2. Escolha... Caso, hereafter called switch.

The availability of the structures vary from language to language, although virtually every programming language provides an if structure. If the contents of the next sections seem too abstract, the sections with flowcharts and visual programming languages can be useful to visualize conditional structures.

If X, Then Y

Perhaps the most traditional conditional structure, if has the following format:

if (condition) then
begin
    // Block to run provided the condition is true
    // ...
end

// Code continues...

If condition is True, the code block in between begin and end is executed. In the example, the block corresponds the comments in the lines 3 and 4. When the block ends, the code continues in the line that follows end (line 6 which, in this case, is empty).

On the other hand, case condition is False, the code block is ignored. The program continues immediately after the block (that is, in line 6).

To make it easier to read code inside the block, the spacing used to create a new visual level is called indentation. It can be made with spaces or tabulations (tabs). In some languages (such as Python and GDScript), the use of indentation is mandatory to define blocks. In others, such as JavaScript and Lua, symbols as curly brackets define blocks or reserved words define blocks, making the use of indentation optional (although I would still recommend using it to make the code easier to read).

For a first interactive example, you can use the embedded JavaScript interpreter in your browser (shortcut for the console/terminal: F12).

let condition = true
if (condition)
{
    console.log("Condition is true, line is executed.")
}

console.log("This line is always executed.")

In the JavaScript code, { can be thought as begin, and } as end. The output would be:

Condition is true, line is executed.
This line is always executed.

Next, modify the code.

// Variable was declared in the previous example.
condition = false
if (condition)
{
    console.log("Condition is true, line is executed.")
}

console.log("This line is always executed.")

The output will be:

Condition is true, line is executed.
This line is always executed.

Thus, the use of if allows executing or ignoring a line according to a logic value provided as a condition. In the example, the variable condition stores the result. You could modify the condition to any other that is relevant to the solution of your problem. It does not even have to be stored in a variable; it suffices that the result can be verified as a value of the logic data type. For instance:

let name = prompt("What is your name?")
console.log("Hello, ", name, "!")

if (name === "Franco")
{
    console.log("My name is also Franco.")
}

If X, Then Y, Else Z

What one should do when she/he wishes to handle the contrary condition? One option is to invert the condition using the not operator.

if (not condition) then
begin
    // Code to run if the condition is false.
    // not false is true, thus the block would be executed.
    // ...
end

// Code continues...

However, it provides the same limitation of handling only one case.

Another possibility is combining the original code with the first alternative.

if (condition) then
begin
    // Code to run if the condition is true
    // ...
end

if (not condition) then
begin
    // Code to run if the condition is false.
    // ...
end

// Code continues...

As the requirement to handle both cases of a condition is frequent in programming, programming language generally define a complement to if called else. While se handles the case in which the result is True, else allows handling the case on which the result is False.

if (condition) then
    begin if
        // Code to run if the condition is true
        // ...
    end if
else
    begin else
        // Code to run if the condition is false.
        // ...
    end else
end

// Code continues...

This time, case the condition is True, the code block between begin if and end if (lines 2--5) is run. Otherwise, the program will run the code block between begin else and end else (lines 7--10). Both cases are mutually exclusive, that is, running one inhibits the execution of the other. In other words, only one block will be run for the result of given condition.

let your_name = prompt("What is your name?")
console.log("Hello, ", your_name, "!")

if (your_name === "Franco")
{
    console.log("My name is also Franco.")
}
else
{
    console.log("Your name is interesting.")
    console.log("My name is Franco.")
}

console.log("Bye, ", your_name, "!")

Source Code Formatting Styles: Curly Braces and Indentation

In programming languages such as C, C++, Java and JavaScript, blocks for defining scopes of structures can be defined using curly braces.

There are some traditional styles to guide the placement of curly braces and indentation in blocks. For a list, you can consult pages such as indentation style oa Wikipedia.

Some of the most traditional styles include:

  1. Allman:
    if (true)
    {
        console.log("Allman")
    }
    else
    {
        console.log("...")
    }
    1. K&R:
    if (true) {
        console.log("K&R")
    } else {
        console.log("...")
    }
    1. GNU:
    if (true)
      {
        console.log("GNU")
      }
    else
      {
        console.log("...")
      }
    1. Whitesmiths:
    if (true)
        {
        console.log("Whitesmiths")
        }
    else
        {
        console.log("...")
        }
    1. LISP:
    if (true)
        {console.log("Whitesmiths")}
    else
        {console.log("...")}

The names are from the authors, institutions, or programming languages that have popularized the style. To be more precise, some authors (such as K&R) omit the use of curly brackets in some cases, something that I personally dislike and do not recommend (next subsection discusses some reasons).

You can choose the style that you prefer. The most important is keep a consistency to create a standard over the project. In other words, avoid mixing styles.

When there is option, I prefer the Allman style as the first option; K&R as the second. The exception is JavaScript. In JavaScript, I consider the K&R style preferable, for there are cases in which the interpreter generates different code from curly brackets started in a new line. Instead of memorizing exceptions, I would rather adopt a consistent style for the whole project.

Thus, the remaining JavaScript examples will use the K&R style.

Omitting Curly Braces for Expressions in a Single Line

As advanced in the previous section, there are authors who omit the use of curly braces in blocks in some situations. This happens because, in the case that a conditional structure has an expression in a single line, the use of curly braces can be omitted.

if (true)
    console.log("1")

if (true) {
    console.log("1")
}

The previous uses are equivalent. Case the conditional structure defines more than one expression, curly braces are required.

if (true) {
    console.log("1")
    console.log("2")
}

Otherwise, the rule a single line of code is valid, generating code that can be potentially different from what was expected.

// Problem.
if (false)
console.log("1")
console.log("Always run.")

// The previous code is equivalent to:
if (false) {
    console.log("1")
}
console.log("Always run.")

If curly braces are omitted, some situations can become confuse and lead to errors, if you do not take care. For instance:

if (true)
    console.log("1")
    if (true)
        console.log("2")
    else        console.log("3")

    console.log("4")

The previous code is equivalent to the following:

if (true) {
console.log("1")
}

if (true) {
    console.log("2")
} else {
    console.log("3")
}

console.log("4")

Incorrect indentation can lead to a misleading interpretation of the code. Therefore, in languages that use curly braces for blocks (such as JavaScript), the indentation is irrelevant to define the structure. The curly braces (or their omission) are important to define the block.

Particularly, I prefer always to use curly braces. Besides making the code block explicit, the use avoid some situations that can be confusing, as the previous.

The next block provides another example that requires caution if curly braces are omitted.

if (true)
    if (false)
        console.log("1")
    else        console.log("2")

In particular, every else matches the closest if (that does not yet have a respective else). The single line rule is still valid. Thus, in the previous example, the else matches the if from line 2.

Besides, modifications to code without curly braces require special attention. What does happen if a new line is inserted between the if and else?

if (true)
    if (false)
        console.log("1")
        console.log("1.1")
    else        console.log("2")

With luck, the result would be a syntax error. With bad luck, in some cases, it could result in a non-intentional modification of the structure:

if (true) {
    if (false) {
        console.log("1")
    }
    console.log("1.1")
} else {    console.log("2")
}

Thus, I prefer always to define blocks explicitly using curly braces.

Nested If

It is possible to add conditional structures inside of other conditional structures. This kind of used is called nesting.

let number = parseInt(prompt("Type an integer number"))
if (number > 0) {
    console.log("The number is positive.")
    if (number < 10) {        console.log("The number is less than 10.")    } else {        if (number === 10) {            console.log("The number is equal to 10.")        } else {            console.log("The number is greater than 10.")        }    }} else {
    if (number < 0) {
        console.log("The number is negative.")
    } else {
        console.log("Zero.")
    }
}

There are situations on which nesting define mutually exclusive conditions. The highlighted parts of lines 4--12 are examples of mutually exclusive conditions (a number only has the value of itself).

To ease writing and reading the code, some programming languages define a different keyword to mark the use of nesting for mutually exclusive conditions, such as elseif or elif. In languages that do not provide them (such as JavaScript), it is still possible to modify the code to make it more readable.

let number = parseInt(prompt("Type an integer number"))
if (number > 0) {
    console.log("The number is positive.")
    if (number < 10) {        console.log("The number is less than 10.")    } else if (number === 10) {        console.log("The number is equal to 10.")    } else {        console.log("The number is greater than 10.")    }} else {
    if (number < 0) {
        console.log("The number is negative.")
    } else {
        console.log("Zero.")
    }
}

As the last else matches the closest if, the implementation is equivalent for mutually exclusive cases.

Ternary If

Some programming languages provide an operator for the if command called ternary if or ternary conditional.

It is usually written in the form condition ? (resultForTrue) : (resultForFalse). In the operator, ? corresponds to the then part, while the : corresponds to the else part. Both are required.

The results for both parts must be an expression that return a value as a result. For instance, for JavaScript:

let your_name_again = prompt("What is your name?")
console.log("Hello, ", your_name_again, "!")

let message = (your_name_again === "Franco")
               ? "My name is also Franco."
               : "Your name is interesting.\nMy name is Franco."
console.log(message)

console.log("Bye, ", your_name_again, "!")

To make it easier to identify the parts, the results for each part are written in a new line. The use of parentheses in the condition is also optional, though I particularly prefer to use them, as I consider they make the code easier to read. Nevertheless, it also would be valid to write the entire expression in a single line and without the parentheses for the expression:

message = your_name_again === "Franco" ? "My name is also Franco." : "Your name is interesting.\nMy name is Franco."
console.log("Bye, ", your_name_again, "!")

It is also possible to nest the ternary operator.

let a_number = parseInt(prompt("Choose a number."))
let message = (a_number > 0)
               ? "The number is positive."
               : (a_number < 0)
                 ? "The number is negative."
                 : "The number is zero."
console.log(message)

If versus Ternary If

You may be wondering when to use the if command and when to use the ternary if.

The if command can always be used.

The ternary if operator is useful to write code in functional style (instead of procedural). At this time, a limitation of the ternary if is the obligatorily that the result be a single expression. After introducing subroutines, a function can be created to remove the limitation.

Still, you can choose the one that you prefer or the one that makes the code easier to read. Personally, I would avoid using the ternary operator for long or complex expressions, or those with several levels of nesting.

Switch Y, Case X

Besides if, some programming languages provide a conditional structure called switch. The switch structure provides a practical form of selecting one among many values, avoid the need to nest multiple if structures in sequence.

let number = parseInt(prompt("Choose an integer number."))

switch (number) {
case 1:
    console.log("One.")
    break
case 2:
    console.log("Two.")
    break
case 7:
    console.log("Seven.")
    break
case 99:
    console.log("Ninity-nine.")
    break
default:
    console.log("Another number: ", number)
    break
}

default (or other case) is the standard option for cases that were not previously contemplated. If it is omitted, the block ends without processing other possible cases. Case there are multiple non-considered values, compilers normally emit a warning about it.

In programming languages without the switch structure, the previous block could be written as:

let number = parseInt(prompt("Choose an integer number."))

if (number === 1) {
    console.log("One.")
} else if (number === 2) {
    console.log("Two.")
} else if (number === 7) {
    console.log("Seven.")
} else if (number === 99) {
    console.log("Ninity-nine.")
} else {
    console.log("Another number: ", number)
}

To make it easier to match the switch with the if implementations, it is possible to modify the indentation and create scopes for each of the cases. In particular, this also allows creating local variables for each case.

let number = parseInt(prompt("Choose an integer number."))

switch (number) {
    case 1: {
        console.log("One.")
        break
    }
    case 2: {
        console.log("Two.")
        break
    }
    case 7: {
        console.log("Seven.")
        break
    }
    case 99: {
        console.log("Ninity-nine.")
        break
    }
    default: {
        console.log("Another number: ", number)
        break
    }
}

How switch works often varies among programming languages. In some, such as C, C++ and JavaScript, you should use break to finish code for each case. If break is not used, the following cases will be run until the indentation of the first break or the end of the structure.

let number = 1

switch (number) {
case 1:
    console.log("One.")
case 2:
    console.log("Two.")
case 7:
    console.log("Seven.")
    break
case 99:
    console.log("Ninity-nine.")
    break
default:
    console.log("Another number: ", number)
    break
}

In this modified example, the omission of break for the cases 1 and 2 will generate different answers if compared to the original code. In cases that such use is intentional, it becomes possible to write compact code by defining common cases first. For instance, if the goal of the previous block was to write all the names in full of the numbers until the number 7, the code would be correct.

Furthermore, some programming languages restrict the types that can be used in the switch. For instance, C and C++ only allow to use numeric values (in other words, it is not possible to use strings).

Therefore, the following code is valid for languages that allow using strings with switch, as JavaScript, though it is not valid in languages such as C.

let number_in_full = "One"
switch (number_in_full.toLowerCase()) {
case "one":
    console.log("1.")
    break
case "two":
    console.log("2.")
    break
case "seven":
    console.log("7.")
    break
case "ninity-nine":
    console.log("99.")
    break
default:
    console.log("Another number: ", number)
    break
}

There also exists languages that provide commands for switch with more features, as intervals of values and pattern matching. At times, such command is called match instead of switch, as match for GDScript (documentation).

Conditional Structures in Programming

Visual resources such as flowcharts and visual programming languages can be useful to visualize conditional structures. Unfortunately, such resources are not accessible to everyone (as they require sight).

Fluxogramas: Flowgorithm

In Flowgorithm, conditional structured are available in the block If. The If block has two parts: True (True), used case the condition results True. In other words, True corresponds to the then part. The part False, for the False case, corresponds to the else part. The code for each part should be inserted at the respective side.

The condition for the block is defined by modifying the value of the block. To do this, you can double-click the inserted If block. The condition must result in a logic value.

Example of use of conditional structures in Flowgorithm using the English interface.

The following code snippet contains the transcription of the text in the image.

Main

Boolean showMessage
showMessage = true

If showMessage
    False
    True
    Output "Hello! My name is Franco."


Integer number
number = 1

If number < 0
    False
        If number > 0
            False
                Output "Zero."
            True
                Output "Positive number."
    True
        Output "Negative number."

If number == -1
    False
        If number == 0
        False
            If number == 1
            False
                Output "Another number."
            True
                Output "One.
        True
            Output "Zero."
    True
        Output "Minus one.

End

One benefit of flowcharts is the greater use of interpreting the program. You follow the arrow and choose the path of the alternative according to the condition. In the case of Flowgorithm, the program always flows from top to bottom. When a if block is reached, the program forks into two options: one case the condition is true, another if it is false. When the block ends, the program joins into a single path again, which can be forked again on each new if block.

In particular, the running the project step-by-step allows to visualize how each instruction is followed. If you are using Flowgorithm, I would recommend using it to watch the program running.

Visual Programming Languages: Scratch

Conditional structures in Scratch are available at the Control side menu. Scratch provides only the if structure for conditions, as two different blocks. The first is called if _ then, while the second provides if _ then and else. The condition used for the if must be a logic value.

Example of use of conditional structures in Scratch in English.

To make it easier to read the code, show_message was defined as a string instead of a logic value (Scratch does not provide constants for True and False). A value yes shows the message; any other value omits it.

The code in Scratch can provide a way to visualize the structure of the program. It can be noted that every resource fits others to write programs. For instance, the condition if requires a logic value, which can be generated from a relational or logic operator.

Besides, each possible path of if ends in a specific point. After it finishes, the program continues in the block that follows the if block.

Textual Programming Languages: JavaScript, Python, Lua and GDScript

JavaScript has been previously used in the initial examples of this page. This section expands the syntax of conditional structures for the Python, Lua and GDScript languages.

JavaScript, Python, Lua and GDScript provide the conditional structure if. In JavaScript, the parentheses are part of the structure. Thus, the language requires writing if (condition). In Python, Lua and GDScript, they are optional (though I prefer to write them). Therefore, if condition and if (condition) are equivalent in the three languages.

Only JavaScript and GDScript provide a structure for switch. In JavaScript, parentheses are obligatory (switch (value)); in GDScript, the use is optional. In Python and Lua, a mutually exclusive sequence of if and else must be used. Another possibility is to simulate a switch structure using a directory (Python) or a table (Lua). The value for other cases (default) occurs when the value does not exist in the data structure. However, as data structures have not yet been commented, the examples will use nested ifs.

let show_message = true
if (show_message) {
    console.log("Hello! My name is Franco.")
}

let number = 1
if (number < 0) {
    consolel.log("Negative number.")
} else if (number > 0) {
    console.log("Positive number.")
} else {
    console.log("Zero.")
}

switch (number) {
case -1:
    console.log("Minus one.")
case 0:
    console.log("Zero.")
    break
case 1:
    console.log("One.")
    break
default:
    console.log("Another number.")
    break
}
show_message = True
# Use of parentheses is optional.
if show_message:
    print("Hello! My name is Franco.")

number = 1
if (number < 0):
    print("Negative number.")
elif (number > 0):
    print("Positive number.")
else:
    print("Zero.")

if (number == -1):
    print("Minus one.")
elif (number == 0):
    print("Zero.")
elif (number == 1):
    print("One.")
else:
    print("Another number.")
local show_message = true
-- Use of parentheses is optional.
if show_message then
    print("Hello! My name is Franco.")
end

local number = 1
if (number < 0) then
    print("Negative number.")
elseif (number > 0) then
    print("Positive number.")
else
    print("Zero.")
end

if (number == -1) then
    print("Minus one.")
elseif (number == 0) then
    print("Zero.")
elseif (number == 1) then
    print("One.")
else
    print("Another number.")
end
extends Node

func _ready():
    var show_message = true
    # Use of parentheses is optional.
    if show_message:
        print("Hello! My name is Franco.")

    var number = 1
    if (number < 0):
        print("Negative number.")
    elif (number > 0):
        print("Positive number.")
    else:
        print("Zero.")

    # Use of parentheses is optional.
    match number:
        # Each case requires indentation.
        -1:
            print("Minus one.")
        0:
            print("Zero.")
        1:
            print("One.")
        # Other case or default.
        _:
            print("Another number.")

In the examples, it is important noticing how each language defined blocks and scopes.

  • JavaScript: blocks are defined using curly braces. The block starts with { (left curly braces) and finishes with } (right curly braces). Indentation is optional, though recommended;

  • Lua: blocks are defined using keywords. The block starts with then and finishes with end. For intermediate conditions, the next block starts on elseif or else. Indentation is also optional, though recommended;

  • Python and GDScript: blocks are defined with indentation. To start a new block, you must increase the indentation by a level. To end a block, you must decrease the indentation by a level. The indentation, therefore, is required and part of the language's syntax.

    For instance, for indentation using 4 spaces:

    • First level: 0 spaces;

    • Second level: 4 spaces;

    • Third level: 8 spaces...

      And so on. The number of spaces is of your choice, though it should be consistent. For instance, to advance from the second to third level, the next line must be started with 8 spaces instead of 4. To return from the third to the second level, the next line should start with 4 spaces instead of 8.

      For indentation using tabulations:

    • First level: 0 tabulations;

    • Second level: 1 tabulations;

    • Third level: 2 tabulations...

      And so on.

As previously commented in text editors for programming, the TAB key will add a tabulation of the number of spaces to the next level. The combination of Shift TAB performs the reverse operation: it removes a tabulation or the required number of spaces to return the previous level. In some text editors, such as GNU Emacs, TAB almost always define the correct indentation for each level. To alternative among levels, you can press the key again.

In the remaining examples and next topics, I will use parentheses for conditional structures even when they are optional. Eu prefer to use them by habit. I also use parentheses for logic value assignments, because I think they are easier to read. If you wish to type less, it is not necessary to type them in your projects for the Python, Lua and GDScript languages.

Examples

Conditional structures are one of the resources that make computers more versatile and powerful machines than calculators. With conditions, you can define arbitrary processing for different classes of values in your application, changing the behavior of the program according to its current state.

Even or Odd?

In relational operations, it was only possible to show True or False as the output of comparisons. With conditional structures, you can choose more appropriate messages for each possible result.

An illustrative example is writing whether a number provided as input is even or odd. After all, it is easier to read and understand that 2 is even or 3 is odd than 2 is even? True or 3 is even? False.

let number = parseInt(prompt("Type an integer number: "))
let remainder = number % 2
if (remainder === 0) {
    console.log(number, " is even.")
} else {
    console.log(number, " is odd.")
}
number = int(input("Type an integer number: "))
remainder = number % 2
if (remainder == 0):
    print(number, " is even.")
else:
    print(number, " is odd.")
print("Type an integer number: ")
local number = io.read("*number")
local remainder = number % 2
if (remainder == 0) then
    print(number, " is even.")
else
    print(number, " is odd.")
end
extends Node

func _ready():
    # Numbed defined in code, because GDScript does not allow reading from the terminal.
    var number = 1
    var remainder = number % 2
    if (remainder == 0):
        print(number, " is even.")
    else:
        print(number, " is odd.")

It is possible to avoid declaring the remainder variable by using (number % 2) == 0 directly as the condition. The operator == must be swapped by === in JavaScript.

Partial Data Validation

When you request the input of a data value of a given type to a user, what does happen if the person provides a value with an unexpected type? For instance, text such as "Franco" instead of a number such as -123?

The answer is an error. With conditional structures, it is possible to determine whether the provided input is valid or not before trying to process it.

The following program use if to determine if the read value is an integer number. If it is, the program writes the double of the value and ends. Otherwise, the program writes an error message and ends.

let number = parseInt(prompt("Type a number: "))
if (!isNaN(number)) {
    console.log("2 * ", number, " = ", 2 * number)
} else {
    console.log("The provided value is not a number.")
}
try:
    # int() / float()
    number = int(input("Type a number: "))
    print("2 * ", number, " = ", 2 * number)
except ValueError:
    print("The provided value is not a number.")
print("Type a number: ")
local number = io.read("*number")
if (number ~= nil) then
    print("2 * ", number, " = ", 2 * number)
else
    print("The provided value is not a number.")
end
extends Node

func _ready():
    # Numbed defined in code, because GDScript does not allow reading from the terminal.
    var value = "Franco"
    # is_valid_float() / is_valid_integer()
    if (value.is_valid_integer()):
        var number = int(value)
        print("2 * ", number, " = ", 2 * number)
    else:
        print("The provided value is not a number.")

How one can find what is the value returned by a read command or function in the case of an invalid value? By consulting the documentation.

  • JavaScript: parseInt() (documentation) and parseFloat() (documentation) return NaN (not a number) in case of error. One can use the function isNaN() (documentation) to test whether a value is NaN;
  • Python: the language uses exceptions to designate about errors instead of return values. int() and float() emit an exception called ValueError (documentation). As the material has not yet described exceptions: exceptions are exceptional situations that can serve do denote errors. Exception handling (in languages that support it) is performed similarly to conditional structures, though they use a special structured called try... catch (or try... except). The part with try assumes that no error will occur. If an error does occur, it is handled in the part catch (or except) for specific types of exceptions. In the case of the conversion, it is called ValueError;
  • Lua: io.read() uses file.read() (documentation) using the standard input stdin as the input file. The documentation informs that the function returns nil on error.
  • GDScript: the verification uses the methods is_valid_integer() (documentation) for integer numbers and is_valid_float() (documentation) for real numbers. Both return true case the text represents a number, or false, otherwise.

If you are wondering why this section is called "partial validation", the reason is that is not possible to request the read of a new value and ensure that it will be valid using conditional structures alone. For instance, if the new provided value is also invalid, it would be necessary to duplicate code and try again.

The problem is: how many times should the code be replicated? Potentially infinite times.

A strategy could be fixing an upper limit for wrong attempts (for instance, 3). However, it is limited. For a more robust solution, it is possible to use repetition structures to request rereads until the input of a valid value. Repetition structures will be one of the next topics of the material.

Classifying Triangles According the Sides' Measurements

Depending on the measurements of its sides, a triangle can be:

  • Equilateral, if the measurements of all sides are equal;
  • Isosceles, if the measurements of two sides are equal;
  • Scalene, if the measures of all sides are different.

There are different ways to implement a solution for the problem. Before consulting a possible solution below, try to think on yours. When you are learning, the best solution is your own.

Naturally, a solution is only a solution if it is correct. To test your solution, you can consider the following triangles with sides , and as test cases:

  • , , : equilateral;
  • , , : isosceles;
  • , , : isosceles;
  • , , : isosceles;
  • , , : scalene;
  • , , : it is not a triangle (all sides must have positive measurements).

It is fundamental to test your programs. The fact that a program compiles of finishes is not a guarantee that the solution is correct (it can only support that the program is syntactically correct). Thus, a good starting point is solving the problem manually to create test cases, with specific inputs and expected answers. A program that passes all test cases is not, necessarily, correct, though a failure in any test case suggests that there exists problems case the obtained result does not match the expected one.

let side_a = parseFloat(prompt("A = "))
let side_b = parseFloat(prompt("B = "))
let side_c = parseFloat(prompt("C = "))

if ((side_a <= 0.0) || (side_b <= 0.0) || (side_c <= 0.0)) {
    console.log("Invalid measurements for one or more sides.")
} else {
    if (side_a === side_b) {
        if (side_b === side_c) {
            console.log("Equilateral triangle.")
        } else {
            console.log("Isosceles triangle.")
        }
    } else if ((side_a === side_c) || (side_b === side_c)) {
        console.log("Isosceles triangle.")
    } else {
        console.log("Scalene triangle.")
    }
}
side_a = float(input("A = "))
side_b = float(input("B = "))
side_c = float(input("C = "))

if ((side_a <= 0.0) or (side_b <= 0.0) or (side_c <= 0.0)):
    print("Invalid measurements for one or more sides.")
else:
    if (side_a == side_b):
        if (side_b == side_c):
            print("Equilateral triangle.")
        else:
            print("Isosceles triangle.")
    elif ((side_a == side_c) or (side_b == side_c)):
        print("Isosceles triangle.")
    else:
        print("Scalene triangle.")
print("A = ")
local side_a = io.read("*number")
print("B = ")
local side_b = io.read("*number")
print("C = ")
local side_c = io.read("*number")

if ((side_a <= 0.0) or (side_b <= 0.0) or (side_c <= 0.0)) then
    print("Invalid measurements for one or more sides.")
else
    if (side_a == side_b) then
        if (side_b == side_c) then
            print("Equilateral triangle.")
        else
            print("Isosceles triangle.")
        end
    elseif ((side_a == side_c) or (side_b == side_c)) then
        print("Isosceles triangle.")
    else
        print("Scalene triangle.")
    end
end
extends Node

func _ready():
    var side_a = 3
    var side_b = 4
    var side_c = 5

    if ((side_a <= 0.0) or (side_b <= 0.0) or (side_c <= 0.0)):
        print("Invalid measurements for one or more sides.")
    else:
        if (side_a == side_b):
            if (side_b == side_c):
                print("Equilateral triangle.")
            else:
                print("Isosceles triangle.")
        elif ((side_a == side_c) or (side_b == side_c)):
            print("Isosceles triangle.")
        else:
            print("Scalene triangle.")

For an additional example, the implementation verify whether all the provided sides are positive. If you wish to improve the solution, you can consider the triangle inequality to verify whether the provided sides can, in fact, form a triangle.

Furthermore, it is possible to reorganize the solution to make the code slightly more compact. Can you identify how to do it?

New Items for Your Inventory

Tools:

  • Test cases.

Skills:

  • Creation of conditions;
  • Definitions of branches;
  • Input verification.

Concepts:

  • Branches;
  • Jumps (conditional and unconditional);
  • Control flow;
  • Structured programming;
  • Sequence;
  • Selection;
  • Iteration;
  • Conditional structures.

Programming resources:

  • Source code formatting and indentation styles;
  • If command;
  • Switch command;
  • Ternary if operator;
  • Condition nesting.

Practice

With conditional structures, you can improve the output of your solutions for the exercises from relational operations and logic operations.

Now, it is also possible to solve more complex problems. An important part of learning programming is discovering how to combine the available pieces to solve problems. It is possible to solve every problem listed next with the concepts presented hitherto, although you will have to think and be creative to solve some of them.

  1. Read the value of a name. Compare the value with your name. If the names are equal, write a message.

  2. Read the value of two numbers. If the numbers are different, write what is the largest and what is the smallest value. Otherwise, write that the numbers are equal.

  3. Read three numbers. Write the numbers in ascending order (from the smallest to the largest). Next, write the values in decreasing order (from the largest to the smallest).

  4. Write a menu with options using conditional structures. The menu can map numbers to options. For instance:

    1. Write "Franco";
    2. Write "Hello!";
    3. Write "Bye!".

    Read the value of an option. For instance, if a user provides the value 1, the program must write Franco.

    You can also use letters or words as the value for accessing an option (for instance, a, b and c, or name, greeting and goodbye).

  5. Create a calculator with the basic arithmetic operations (addition, subtraction, multiplication and division). The calculator must read two values and an operator, then perform the necessary calculations and write the result. Be careful with divisions by zero! Tip: the choice an operation can use a menu such the one from the previous exercise.

  6. Read three values for internal angles of a triangle. Is the sum of the internal angles equal to 180°? Write a message accordingly.

  7. Read three values for the internal angles of a triangle. Classify the triangle according to its angles.

    • If all internal angles are less than 90°, it is an acute angle triangle;
    • If one of the internal angles is equal to 90°, it is a right angle triangle;
    • If one of the internal angles is above 90°, it is an obtuse angle triangle.

    You should note that only one of the angles can be equal or above 90°. Otherwise, the sum of the internal angles will exceed 180°.

  8. Read the name of a month. Tell how many days it has. You can choose a number of days for February, or inform both possibilities (28 days or 29 days for a leap year).

  9. Consider a column of the periodic table of the chemical elements. For instance, you can consider the group 1 (alkali metals), composed by lithium (Li), sodium (Na), potassium (K), rubidium (Rb), caesium (Cs), and francium (Fr). Read the two initials and tell if it belongs to group. If it does, write the name of the corresponding element. For instance, the input Fr would provide the element Francium as the result.

  10. In the game Rock, Paper, Scissors, two people choice one among the three previous value as their play. If both values are equal, the result is a draw. For the other combinations:

    • Rock beats scissors;
    • Scissors beat paper;
    • Paper beat rock.

    Read two plays and write the result.

    The implemented game will not be very fair, as the second person could read the play of the first. Can you think about a way to hide the first play before reading the second value?

    A better way to modify the solution consists in drawing a move, something that can be performed using pseudo-aleatory numbers, which will be presented with repetition structures.

Next Steps

Conditional structures make computers more powerful tools than mere calculators, as they allow definition of branches and alternative flows to run a program.

With conditional structures, it becomes possible to solve more complex problems. With more complex programs, the tendency is that the size of the programs (in lines of code) does also start increasing. Until now, whenever there was a need to perform a very same processing, it was necessary to duplicate code. It is not a good programming practice to duplicate code.

In general, it is ideal to create code that can be used with multiple values, whenever required. The next topic will enable the creation of reusable code blocks, called subroutines, a term that includes functions, procedures and methods.

You have already used subroutines in your programs (for example, for value conversion, or even for data input or output in some languages). Now you will become able to create your own, as well as your own libraries.

  1. Introduction;
  2. Entry point and program structure;
  3. Output (for console or terminal);
  4. Data types;
  5. Variables and constants;
  6. Input (for console or terminal);
  7. Arithmetic and basic Mathematics;
  8. Relational operations and comparisons;
  9. Logic operations and Boolean Algebra;
  10. Conditional (or selection) structures;
  11. Subroutines: functions and procedures;
  12. Repetition structures (or loops);
  13. Arrays, collections and data structures;
  14. Records (structs);
  15. Files and serialization (marshalling);
  16. Libraries;
  17. Command line input;
  18. Bitwise operations;
  19. Tests and debugging.
  • Informatics
  • Programming
  • Beginner
  • Computational Thinking
  • Learn Programming
  • Python
  • Lua
  • Javascript
  • Godot
  • Gdscript
  • Scratch
  • Flowgorithm