LDC #98: Conditionals, If You Want Me To

Language directives allow you to change the code the programming language sees when it runs. We’ve talked a little bit about directives before, but today I will take a look at a subset of directives: conditionals. Conditionals allow a programmer to add or remove sections of code based on the existence of other directives. This means that it’s easy to build larger suites of code while allowing sections of code to be taken out without causing errors during runtime.

There are five conditional directives:

–  #ifdef [name]
–  #ifndef [name]
–  #elseif
–  #elif
–  #endif

You can think of these directives as opening and closing braces for “if” statements. You use one of the first two to start a section, (optionally) use #elif or #elseif to do something if the first conditional is not met, and you close the section using #endif.

Conditional Directives

The usage is pretty simple: replace [name] with the name of a potential defined variable. #ifdef checks to see if the [name] is defined, while #ifndef checks to see if [name] is not defined. If the statement is true, Legato will execute the code underneath until it encounters the #endif directive.

Let’s look at a very simple example:

#define TEST 0;

int main() {

#ifdef TEST
    MessageBox("A");
#ifndef TESTER
    MessageBox("B");
#endif
    MessageBox("C");
    
    return TRUE;
    }

Here we look to see what we have defined at the top of the file and put out some message boxes. For the example, we’ve defined TEST as zero. When we run the script, we will have all three message boxes shown, because we have TEST defined, we do not have TESTER defined, and the third message box is always shown. If we were to change the script and define TESTER instead, only message box “C” will be shown. Finally if neither are defined, both “B” and “C” are shown.

The final thing to keep in mind is that this checks to see if anything has been defined in the entire compilation process. If file A.ls includes B.ls and B.ls defines TEST, when main() is run in A.ls anything that references TEST will have that definition.

Now that we’ve discussed how conditionals work, let’s discuss some reasons why someone would want to use conditionals. The usual reason for using conditionals is to allow the testing of individual steps within a process. For example, if we were creating a multi-step process of changing a file we could split each step into a different file.

Josh’s Big File Project of Automation
1. Remove all clutter
2. Polish all tables
3. Eat all the cookies
4. Attach file to project
5. File to SEC

This project would have seven different files, one for each step and two to control everything. The first control file would simply define roles. In the example process case, not everyone should have permissions to do everything in the process. My co-workers, for example, don’t get to eat all of the cookies or file the project. Only the manager gets to do those. So we would use the first control file to define the “worker” and “manager” roles.
The second control file would manage the process, which we will discuss a little later.

In each step file, we would have a section that looks something like this:

#ifndef _INCLUDE_FILE
                                                                        /****************************************/
int main() {                                                            /* Main Entry (testing only)            */
                                                                        /****************************************/
    int                 rc;                                             /* Return Code                          */

    do_function(“location_of_test_file”);                               /* Do the thing                         */
    return ERROR_NONE;                                                  /* Return value (does not matter)       */
    }                                                                   /* end setup                            */

#endif

This section allows us to stop errors from occurring while we run the script from the control file (which includes all the step files), but also allows us to run the script directly in order to test just this one step of the project. “_INCLUDE_FILE” is important to note, as it is a pseudo definition that only shows up in files that are included. This means that if the script is run from the control file, it is defined, but if the script is run directly in the IDE it is not defined.

Finally, finishing our example, we would have to have a control file that runs each step of the project. It would have a section that would look something like this:

run_project_step_1(“Filename”);
run_project_step_2(“Filename”); 
#ifndef WORKER
run_project_step_3(“Filename”);
#endif
run_project_step_4(“Filename”);
#ifdef SUPERVISOR
run_project_step_5(“Filename”);
#endif

This code would be in our main function of the control file, which calls all of the functions available to the roles of the user.

Conditional statements are a great way to give extra control and flexibility over code to the developer. It allows us to hide or show functions depending on where a script is being run from, which allows us to build larger projects of functions and still be able to test individual pieces easily. Easier testing means that the level of bugs in our code decreases, which in turn means more cookies for everyone.

 

Joshua Kwiatkowski is a developer at Novaworks, primarily working on Novaworks’ cloud-based solution, GoFiler Online. He is a graduate of the Rochester Institute of Technology with a Bachelor of Science degree in Game Design and Development. He has been with the company since 2013.