Installing JS++

Charles Kozeny-PellingBy Charles Kozeny-Pelling

Charles Kozeny-Pelling is a graduate of the University of Oxford

To use JS++, the first step is to install it on your computer. Go to the JS++ home page at www.onux.com/jspp and click on the "Install Now" button. The website will detect which kind of operating system your computer uses (Windows, Mac OS, or Linux), so when you click on the install button, you’ll get the right download for your computer.

Installing JS++

Installing on Windows

After you click "Install Now", you’ll see a pop-up which says something like "setup-JS++-0.7.0.exe" (don’t worry if it’s slightly different). Click on it. You’ll be asked to choose where on your computer you’d like JS++ to be installed: click "Next" to select the default location. You’ll then see a "Select Additional Tasks" box, which gives you the options: "Add to PATH variable" and "Add to context menu".

Installing on Windows

Make sure both options are selected, and click "Next". Click "Install" to complete the installation.

Note: To use JS++, you will need to have a software package named Visual C++ Redistributable installed on your computer. You will probably already have it installed, since many applications require it. If you do not have it installed, however, you can download it here: https://www.microsoft.com/en-us/download/details.aspx?id=48145

Installing on Mac OS

After you click "Install Now", you’ll download a file named something like "JS++-0.8.1-macosx.tar" (don’t worry if it’s slightly different).

Installing on Mac OS

Double click on the file to extract the JS++ folder. Open this folder and find the "js++" executable file. Right click and copy this file. From the Finder’s "Go" menu, select "Go to Folder" and type in "/usr/local/bin" without the quotes.

Installing on Mac OS

Right click and paste the "js++" file into this directory.

Open the Terminal app, and navigate to the "/usr/local/bin" directory: to do this, type "cd /usr/local/bin".

Installing on Mac OS

Type "ls" to see a list of files in this directory: you should see the file "js++" listed there. Finally, type "chmod +x js++" without the quotes.

Installing on Linux

Linux installation works in a similar way to Mac OS installation (see above). After clicking the install button, you’ll need to find the "js++" executable file and copy it to the "/usr/local/bin" directory. Then open the terminal, navigate to the "/usr/local/bin" directory, and type in "chmod +x js++" without the quotes.

Hello World - Your First JS++ Program

Charles Kozeny-PellingBy Charles Kozeny-Pelling

Charles Kozeny-Pelling is a graduate of the University of Oxford

In this tutorial, you’ll write your first JS++ program. The program’s purpose will be to get an HTML document to display "Hello World!" when opened with a web browser.

Code Editor

Before you can start writing code, you’ll need to decide which application to use to do the writing.

For the rest of these tutorials, we’ll assume that you’re writing your code using Visual Studio Code.

Writing the code

Let's get started. To group your JS++ files together for this tutorial, create a new folder and name it "HelloWorld". Then create a new file and name it "HelloWorld.jspp" (without the quotes). Write in the following code:

            // My first JS++ program
            // Adds the text "Hello World!" to the page
            external $;

            $("#content").text("Hello World!");
            

Don’t worry what the code means – we’ll get to that later. For now, let’s focus on getting your program up and running. Save HelloWorld.jspp to your HelloWorld folder. Then create a second file named "HelloWorld.html" and write in the following code:

            <!DOCTYPE html>
            <title>My first JS++ program</title>

            <body>

            <p id="content"></p>

            <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
            <script src="HelloWorld.jspp.js"></script>

            </body>
            </html>
            

Save this file to your HelloWorld folder.

Running the program on Windows

You should now see two files in your HelloWorld folder: HelloWorld.jspp and HelloWorld.html. Right click on HelloWorld.jspp and select "Compile with JS++". Now open HelloWorld.html with a web browser. If everything has worked, the document should display "Hello World!".

Running the program on Mac OS / Linux

Open the Terminal, and navigate to your HelloWorld directory. Type in "js++ HelloWorld.jspp" without the quotes. Now open HelloWorld.html with a web browser. If everything has worked, the document should display "Hello World!".

> js++ HelloWorld.jspp

How did it work?

You might have noticed that when you compiled HelloWorld.jspp by following the instructions above, a new file named "HelloWorld.jspp.js" was created in your HelloWorld folder. This is a JavaScript file and the code it contains is executed by your browser when the browser opens HelloWorld.html. The effect of executing that code is that HelloWorld.html displays "Hello World!".

How does your browser know that it should execute the code in HelloWorld.jspp.js when HelloWorld.html is opened? The answer lies in this line of HelloWorld.html:

            <script src="HelloWorld.jspp.js"></script>
            

The <script> tag in an HTML document either itself contains executable code, or (as in this case) points to another file that contains executable code. The code in question (typically JavaScript) is executed by a browser when the browser is used to open the HTML document. In our case, the effect of executing the code in HelloWorld.jspp.js is to make the document display "Hello World!".What about the other <script> tag in HelloWorld.html:

<script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>

This line refers to a popular JavaScript library called jQuery. jQuery is popular because it simplifies the process of scripting the browser: it lets you do things with less code than you would otherwise have to write.

The jQuery <script> tag is needed in HelloWorld.html because you used jQuery in writing HelloWorld.jspp. Look again at its first line:

external $;

This statement imports the jQuery library into HelloWorld.jspp, thereby enabling you to use jQuery in the code that comes after. (The "$" symbol here is just a shorthand for "jQuery"; we’ll look more generally at external import statements in Chapter 9.)

Now let’s look at the next line, breaking it down into two parts. First, we have:

$("#content")

Here, you use jQuery to select the HTML element with the ID "content":

<p id="content"></p>

Then, in the second part of the line, we have:

.text("Hello World!");

This sets the text of the selected element to "Hello World!".

Since you used jQuery in writing HelloWorld.jspp, it’s also used in the HelloWorld.jspp.js file that was created when you compiled HelloWorld.jspp. That is why the jQuery <script> tag is needed in HelloWorld.html: without it, your browser would not be able to understand the jQuery code in HelloWorld.jspp.js.

Hopefully this should give you a broad outline of the way in which JS++ is used in combination with JavaScript and jQuery, at least in the context of the HelloWorld project. Don’t worry if you feel that you don’t yet have a full grasp of these issues at this stage. As you work your way through the tutorials, you’ll gain a more general understanding of JS++ and its relation to JavaScript and jQuery.

Variables and Data Types

Charles Kozeny-PellingBy Charles Kozeny-Pelling

Charles Kozeny-Pelling is a graduate of the University of Oxford

In this tutorial, we will introduce variables in JS++. Let’s start with an example. Create a new folder and name it "Variables". Then create a new file and name it "Variables.jspp". Write in the following code:

        external $;

        string firstString = "This is a string.";
        int firstInt = 1;
        double firstDouble = 1.1;
        bool firstBool = true;

        $("#string_content").text(firstString);
        $("#int_content").text(firstInt);
        $("#double_content").text(firstDouble);
        $("#bool_content").text(firstBool);
        

Save Variables.jspp to your Variables folder. Then create a second file named "Variables.html" and write in the following:

        <!DOCTYPE html>
        <title>Variables program</title>
        <body>

        <p id="string_content"></p>
        <p id="int_content"></p>
        <p id="double_content"></p>
        <p id="bool_content"></p>

        <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
        <script src="Variables.jspp.js"></script>

        </body>
        </html>
        

Save Variables.html to your Variables folder. Compile Variables.jspp and then open Variables.html in a browser. If everything has worked, your document should display the values of the four variables in Variables.jspp.

Variables and types

When we declared our variables in Variables.jspp, we gave each of them a type: string, int, double, and bool. The fact you can use such typed variables is an important feature of JS++, and represents a key difference with JavaScript. In JavaScript, you declare a variable with the var keyword and such variables are not typed. The same variable might first hold a string, for example, then later a number, and then later a boolean value. In JS++, by contrast, when you declare a variable as belonging to a given type, you tell the compiler that the variable will hold only data of that particular type. So for example, string variables hold sequences of characters, int variables hold integer numbers, double variables hold floating-point numbers, bool variables hold logical values (true and false), and so forth.

What happens if your program accidentally assigns the wrong kind of value to a typed variable? This results in compilation failure, not a runtime error. For example, look again at the line:

bool firstBool = true;

Suppose you change this to:

bool firstBool = "This is a string, not a bool.";

Your program will no longer compile. If you try, the compiler will complain that it cannot convert a string to a bool.

Why is it better for a problem of this kind to cause a compilation failure, rather than a runtime error? The answer is that it makes the bug easier to spot and easier to fix at an earlier stage of development. It becomes less likely that the bug will remain hidden away in some complex part of your code, only to emerge at a crucial stage after your program has gone live. This can be especially useful in large projects and teams. In this respect, JS++ offers an advantage over JavaScript, which does not bring errors of this sort to light at compile time since it does not use typed variables.

Note: JS++ does not force you to use typed variables. You can still use untyped variables if you wish, just as you would do in JavaScript - more on this in Chapter 9. When you do use typed variables, however, their values are guaranteed to be of the right type if the program compiles.

The four types we used in Variables.jspp - string, int, double, and bool – are among the primitive data types of JS++. You can find a full list of them here: JS++ primitive data types

Regarding the numeric primitive data types, it’s worth noting that JS++ contains not only int and double but also byte, short, unsigned int, and unsigned short (the unsigned types can only contain positive numbers). These types vary both in the amount of memory that they use and in the range of numbers that they can hold.

Regarding the textual data types, JS++ contains char as well as string: in a case where you know that a variable should hold a single individual character, it would be appropriate to declare your variable as a char. More generally, the wide variety of primitive data types in JS++ gives you a great deal of flexibility in selecting the most appropriate variable type for your purposes.

JS++ data types are not limited to its primitives. For example, there are also function types, array types, callback types, and user-defined types. We’ll examine all of these in subsequent tutorials. In this tutorial, however, the focus will remain on primitive types.

Declaring and initializing variables

In Variables.jspp, we declared the four variables in separate statements, but we initialized each variable in the same state as we declared it. You don’t have to introduce variables like that, however. For example, you can declare a variable in one statement and then initialize it later:

            bool firstBool;
            // ...
            firstBool = true;
            

You can also declare several variables of the same type in a single statement:

char firstChar, secondChar, thirdChar;

And you can initialize several variables of the same type when you declare them:

char firstChar = `a`, secondChar = `b`, thirdChar = `c`;

What happens if a variable is accessed after it has been declared but before it has been initialized? To see, let’s change the code of Variables.jspp:

            external $;
                
            string firstString;
            int firstInt;
            double firstDouble;
            bool firstBool;

            $("#string_content").text(firstString);
            $("#int_content").text(firstInt);
            $("#double_content").text(firstDouble);
            $("#bool_content").text(firstBool);

If you compile this code and then open Variables.html in a browser, you’ll see that each of the variables is set to a default value: firstString is set to "" (empty string), firstInt and firstDouble are set to 0, while firstBool is set to false. You can see a full list of the default values for JS++ primitive data types via the link above.

Variables and scope

The scope of a variable is the part of the program where that variable is visible (accessible by name). In JS++, a variable’s scope is determined by the code block (a section of code within a pair of curly braces) where it is declared: the variable becomes visible immediately after declaration from any subsequent place in the same block. For example, consider:

            {
                string firstString;
                firstString = "Another string.";
            }
            

Here there is no problem, since the value of firstString is modified after firstString has been declared but within the same block. By contrast, consider:

            {
                string firstString;
            }

            firstString = "Another string.";
            

Now there is a problem: this code won’t compile because firstString is not visible outside the block where it is declared.

How does scope work when a variable is declared outside every explicit code block (i.e. every block defined by a pair of curly braces)? In this case, the variable is visible from anywhere in the file after it has been declared. This also applies to cases where a file doesn’t contain any explicit code blocks, as in Variables.jspp.

Conditionals

Charles Kozeny-PellingBy Charles Kozeny-Pelling

Charles Kozeny-Pelling is a graduate of the University of Oxford

Conditional statements of various kinds play a central role in JS++. In this tutorial, we will look at the basic syntax and some common uses of such statements, and we will also introduce two kinds of expressions that are often used in conditionals: comparison operators and logical operators.

Note: JS++ conditionals, comparison operators, and logical operators work in a similar way to their counterparts in languages such as JavaScript, Java, C++, and C#.

Let’s start by making a new folder - name it "Conditionals". Then make a new file and name it "Conditionals.jspp". Write in the following code:

        external $;

        string colorString;
        bool likesRed = true;
        if (likesRed) {
            colorString = "red";
        }

        $("#content").text(colorString);
        $("#content").css("color", colorString);
        

Save Conditionals.jspp to your Conditionals folder. Then create a second file named "Conditionals.html" and write in the following:

        <!DOCTYPE html>
        <title>Conditionals program</title>
        <body>

        <p id="content"></p>

        <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
        <script src="Conditionals.jspp.js"></script>

        </body>
        </html>
        

Save Conditionals.html to your Conditionals folder. Compile Conditionals.jspp and then open Conditionals.html in a browser. If everything has worked, your document should display "red" in a red font.

"if", "else", and "else if"

Conditionals.jspp shows the syntax of a simple if statement: the keyword if itself, followed by a pair of parentheses holding a condition to check, followed by a block of code in curly braces which executes if and only if the condition is true.

Simple If Diagram

Note: the curly braces around the code block are optional if the block only contains one statement. For consistency and readability, however, it is advisable always to use curly braces.

Although if statements are often used on their own, they are also commonly used together with else statements. Let’s add an else statement to Conditionals.jspp:

            external $;
                
            string colorString;
            bool likesRed = true;

            if (likesRed) {
                colorString = "red";
            }
            else {
                colorString = "blue";
            }
                
            $("#content").text(colorString);    
            $("#content").css("color", colorString);
            

Compile this code and then open Conditionals.html in a browser. The result is the same: the document still displays "red" in a red font. The reason is that the code in an else block only executes if the condition in the associated if statement is false. To get the code in your else block to execute, change the value of likesRed to false: Conditionals.html will then display "blue" in a blue font.

Notice that the else statement doesn’t specify a condition of its own; the only condition that is checked in Conditionals.jspp is likesRed. We simply have one block of code which executes if that condition is true, and another block which executes if it is false.

If Else Diagram

In some cases, however, we want the execution of our code to depend on more than one condition. This is where else if statements can prove useful. An else if statement supplies a condition of its own and an associated code block. The code block executes if the condition is true and all previous conditions (i.e. those associated with earlier if and else if statements) are false. Let’s revise Conditionals.jspp again to show the use of an else if statement:

            external $;

            string colorString;
            bool likesRed = false;
            bool likesBlue = true;

            if (likesRed) {
                colorString = "red";
            }
            else if (likesBlue) {
                colorString = "blue";
            }
            else {
                colorString = "green";
            }

            $("#content").text(colorString);
            $("#content").css("color", colorString);
            

Here the code in the else if block will execute, since its likesBlue condition is true whereas the likesRed condition specified by the earlier if statement is false. If we change the value of likesBlue to false, however, the code in the else if block will not execute, but the code in the else block will. Play around with the values of likesRed and likesBlue for yourself to see what effect they have on the conditional’s execution.

Comparison operators

Often when we use conditionals, it is because we want the execution of our code to depend on the result of a comparison of some kind. For example, suppose we want to check whether the value of a tempInCelsius variable is equal to 0, and have some code execute if it is. We would write:

            if (tempInCelsius == 0) {
                // Code to be executed goes here
            }
            

This conditional uses the equality operator "==". An equality comparison returns true if the compared values are equal and false otherwise.

Note: the equality operator "==" is not the same as the assignment operator "=" . Take care with this distinction! If you accidentally use "=" in place of "==", you will introduce bugs into your code which may be hard to spot.

JS++ contains various comparison operators in addition to "==". To extend the temperature checking example, suppose we wanted to check not the exact value of tempInCelsius but rather what range it falls in. Our code might look like this:

            if (tempInCelsius > 30) {
                // Code to execute if temperature is over 30
            }
            else if (tempInCelsius >= 15) {
                // Code to execute if temperature is between 15 and 30
            }
            else {
                // Code to execute if temperature is 14 or below
            }
            

This example uses the greater than operator ">", which returns true if the left operand is greater than the right operand, and the greater than or equal to operator ">=", which returns true if the left operand is greater than or equal to the right operand. You can see the full range of comparison operators here:

Comparison operators in JS++

Logical operators

Sometimes we want code to execute only if multiple conditions are true. To achieve this, one option would be to use nested conditionals, such as the following:

            external $;

            string colorString;
            bool likesRed = true;
            bool likesBlue = true;
                
            if (likesRed) {
                if (likesBlue) {
                    colorString = "I have a wide taste in colors";
                    $("#content").text(colorString);
                }
            }
            

By placing the likesBlue conditional within the likesRed conditional in this way, we ensure that the code in the likesBlue block will execute if and only if both conditions are true.

Although nested conditionals can be used for such purposes, however, they tend to make code difficult to read, particularly when the conditionals involved are complex. An alternative is to use the logical AND operator "&&". Let’s replace our nested conditional with:

            if (likesRed && likesBlue) {
                colorString = "I have a wide taste in colors";
                $("#content").text(colorString);
            }
            

An "&&" statement takes two operands, which will normally both be Boolean expressions. Assuming they are, the statement returns true if both operands are true, and false otherwise. Thus the code above has the same effect as the earlier nested conditional: the code block executes if and only if both likesRed and likesBlue are true. The "&&" conditional is easier to read than the nested conditional, however, so is for that reason preferable.

JS++ contains two other logical operators in addition to "&&": the OR operator "||", and the NOT operator "!". "||" is a binary operator like "&&": it takes two operands. Assuming both are Boolean expressions, the statement returns true if at least one operand is true, and false otherwise. "||" is useful in cases where you want some code to execute if either one condition is true or another is:

            if (likesRed || likesBlue) {
                colorString = "I like at least one color";
                $("#content").text(colorString);
            }
            

"!" differs from "&&" and "||" in that it is a unary operator: it takes a single operand. It returns true if the operand is false, and false if the operand is true. For example:

            if (!likesRed) {
                colorString = "I do not like red";
                $("#content").text(colorString);
            }
            

Note: Although the operands governed by "&&" and "||" will normally be Boolean expressions, they don’t have to be. To cover cases where the operands are non-Boolean, "&&" and "||" are more precisely defined as follows: an "&&" statement returns false if the left operand is false; otherwise it returns the value of the right operand. An "||" statement returns true if the left operand is true; otherwise it returns the value of the right operand.

Switch statements

Sometimes you need your program to handle various different possibilities and to execute different code in each. Although you could achieve this by using a conditional with multiple else if statements, it is often simpler is to use a switch statement. A switch statement evaluates an expression and compares its value with one or more case expressions; if one of these case expressions provides a match, some associated code is executed.

Switch Diagram

Let’s take an example:

            external $;

            string favoriteColor;
            string colorComment;
            favoriteColor = "green";
                
            switch (favoriteColor) {
                case "red":
                    colorComment = "red is fantastic";
                    break;
                case "blue":
                    colorComment = "blue is wonderful";
                    break;
                case "green":
                    colorComment = "green is magical";
                    break;
                case "yellow":
                    colorComment = "yellow is brilliant";
                    break;
                default:
                    colorComment = "I have no favorite color";
                    break;
            }
                
            $("#content").text(colorComment);
            

In this example, the switch statement compares the value of the string favoriteColor with the various case expressions listed. When it finds a match, it executes the associated code. Since the value of favoriteColor is "green", the switch statement executes the code associated with that case: the string colorComment is set to "green is magical".

What is the purpose of the break and default keywords? The break keyword is very important because it’s needed if you want to prevent so-called "fallthrough". Fallthrough happens when a switch statement executes the code associated with one or more cases after the matching case. For example, if you remove the break at the end of the green case, the switch statement will go on to set colorComment to "yellow is brilliant". In some rare situations you may want fallthrough of this sort; if so, you would intentionally omit break. (You would also be advised to add a comment explicitly indicating that the fallthrough was intended.) Usually, however, you will want to include break at the end of each case.

The code in the default clause is executed if none of the case expressions match the original expression. The default clause is optional: if you don’t provide one, then the program resumes execution at the first statement after the switch statement.

Loops

Charles Kozeny-PellingBy Charles Kozeny-Pelling

Charles Kozeny-Pelling is a graduate of the University of Oxford

It often happens in computer programming that you want a piece of code to execute more than once. Loops are programming statements that allow you to handle such cases. JS++ contains loops of various kinds, and we will look at several of them in this tutorial. We will begin, however, by examining two expressions that are used very commonly to facilitate the use of loops: the increment operator "++", and the decrement operator "--".

Note: The increment and decrement operators, and the loop statements that we will examine in this tutorial, work in a similar way to their counterparts in languages such as JavaScript, Java, C++, and C#.

"++" and "--"

To show these operators in action, let’s take an example. Make a new folder and name it "Loops". Then make a new file and name it "Loops.jspp". Write in the following code:

            external $;

            int i = 0;
            $("#content").append("i is now ", i, "; ");
            ++i;
            $("#content").append("i is now ", i, "; ");
            --i;
            $("#content").append("i is now ", i, "; ");
            

Save Loops.jspp to your Loops folder. Then create a second file named "Loops.html" and write in the following:

            <!DOCTYPE html>
            <title>Loops program</title>
            <body>
            <p id="content"></p>
            <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
            <script src="Loops.jspp.js"></script>
            </body>
            </html>
            

Save Loops.html to your Loops folder. Compile Loops.jspp and then open Loops.html in a browser. Your document should show that "++" increases the value of i by 1, and "--" decreases i by 1.

As in various other programming languages, "++" and "--" can be used either before or after the variable. To illustrate the difference between these "prefix" and "postfix" uses, change the code in Loops.jspp to the following:

            external $;

            int i = 0;
            int j = 0;
            j = ++i;
            $("#content").append("j is now ", j, ", and i is now ", i, "; ");    
            j = i++;
            $("#content").append("j is now ", j, ", and i is now ", i, "; ");
            

The variable i is incremented for the first time through the use of the prefix increment operator. This means that i is incremented before its value is used in the statement, and the value of j is therefore set to 1. When i is incremented for the second time, by contrast, it is through the use of the postfix increment operator. This means that i is incremented after its value is used in the statement, and the value of j therefore remains 1. The prefix / postfix distinction applies in exactly the same way to the two versions of the decrement operator.

"while" and "do... while"

Now let’s examine how we can use the increment and decrement operators in loops. We will look at three types of loops in this tutorial: while loops, do... while loops, and for loops. We begin with while loops.

The purpose of a while loop is to make some code - the loop body - execute repeatedly for as long as a particular condition is true. When the condition is no longer true, the loop body ceases to execute.

While Diagram

Let’s take an example. Change the code in Loops.jspp to the following:

            external $;

            int i = 0;
            while (i < 3) {
                $("#content").append("i is now ", i, "; ");
                i++;
            }
            

Here we see the syntax of a while loop: the while keyword, followed by a pair of parentheses holding a condition to be checked, followed by a block of code in curly braces which will execute repeatedly for as long as the condition is true.

In this example, the loop executes three times: once when i is 0, a second time when i is 1, and a third time when i is 2. During the third execution i is incremented to 3; this means that when the condition (i < 3) is next checked, it is found to be false and the loop terminates.

What happens if the condition in a while loop is false from the outset? If so, the loop body will not execute. Your program’s execution simply continues to the first statement following the loop. That might be exactly the behaviour you want; in other cases it might not be. If instead you want your loop to execute at least once before checking whether a condition is true, there is a different kind of loop for that purpose: the do... while loop.

Change the code in Loops.jspp to the following:

            external $;

            int i = 0;
            do {
                $("#content").append("i is now ", i, "; ");
                i++;
            }
            while (i > 10);
            

In a do... while loop, the loop body is written after the do keyword, but before the condition to be checked. The loop executes at least once even if the condition is false on first time of checking, as it is in this example. When the condition is found to be false, the loop terminates.

Do While Diagram

"for"

for loops differ from while and do... while loops in one important respect: the syntax of a for loop is specifically designed to facilitate the use of counter variables. Let’s take a look at an example:

            external $;

            for (int i = 0; i < 2; i++) {
                $("#content").append("i is now ", i, "; ");
            }
            

The syntax of a for loop, as illustrated by this example, is somewhat more complex than that of a while or do... while loop so we will take a little more time to go over it. We can see that a for loop starts with the for keyword, which is then followed by some code in parentheses. The code in parentheses has three components, which are separated by semi-colons. The first part is the initialization component, where we declare our counter variable:

int i = 0;

The second part is the condition component, which provides a test to determine when the loop should terminate:

i < 3;

The third part is the update component, which would typically increment or decrement the counter variable:

i++

The code in parentheses is then followed by the loop body, in a pair of curly braces. The loop body is composed of the statement(s) to be executed.

A for loop proceeds as follows (see also the illustration below). First, the counter variable is initialized. Second, the condition is checked. If it is false then the loop terminates; if it is true then the loop continues to the next step. Third, the loop body executes. Fourth, the update component executes. Fifth, the loop returns to step two and repeats until the condition becomes false.

In our example, the loop body executes twice: once when the counter variable i is 0, and again when i is 1. After the second execution, the update component increments i to 2. This means that when the condition i < 2 is checked, it is found to be false and the loop terminates.

Note: The initialization, condition, and update components of a for loop are all optional, strictly speaking, though one would normally expect to include them. For more information about non-standard uses, see:

JS++ for loops

"break" and "continue"

The break and continue keywords give you extra flexibility in using loops, and both can be used in all the types of loops that we’ve examined. It is important to understand the difference between break and continue, however: break is used to terminate a loop immediately, whereas continue is used to skip to the next iteration.

To illustrate the difference, let’s take an example involving a while loop:

            external $;

            int i = 0;
            while (i < 3) {
                i++;
                if(i == 2) {
                    break;
                }
                $("#content").append("i is now ", i, "; ");
            }
            

If you write this code in to Loops.jspp, compile it, and then open Loops.html in a browser, it will display "i is now 1;". It doesn’t display any more than that since the loop terminates midway through its second iteration, due to the use of break. If you remove break and replace it with continue, however, you will see a different result: Loops.html displays "i is now 1; i is now 3;". This shows that continue doesn’t terminate the loop completely; it only terminates the current iteration, so that the loop skips ahead to the next iteration.

Nesting and labelled loops

Loops can be nested, which means putting one loop inside another. Here is an example of a nested for loop:

            external $;

            for (int i = 0; i < 2; i++) {
                $("#content").append("i is now ", i, "; ");
                for (int j = 0; j < 2; j++) {    
                    $("#content").append("j is now ", j, "; ");
                }
            }
            

In cases such as this, the inner loop runs through all of its iterations for each iteration of the outer loop. In this case, the outer loop executes twice and for each of those two executions, the inner loop executes twice. The inner loop therefore executes four times in total.

If you want to use break or continue in nested loops, it can be useful to label your loops. For example, consider this use of break in a nested loop:

            external $;

            outer: for (int i = 0; i < 2; i++) {
                $("#content").append("i is now ", i, "; ");
                inner: for (int j = 0; j < 2; j++) {    
                    if(j == 0) {
                        break outer;
                    }
                    $("#content").append("j is now ", j, "; ");
                }
            }
            

By labelling the outer loop outer, we make it possible to refer to that loop when using the break statement inside the inner loop. This use of break therefore terminates the outer loop, not just the inner one. If we had not used labels, break would have referred to the inner loop since by default break refers to the innermost loop in which it occurs. Parallel remarks apply to continue: by default it refers to the innermost loop in which it occurs, but it can also refer explicitly to an outer loop via a label.

Functions

Charles Kozeny-PellingBy Charles Kozeny-Pelling

Charles Kozeny-Pelling is a graduate of the University of Oxford

A function is a section of code which contains a set of instructions, where the instructions describe how a particular task is to be accomplished. Functions are declared and may then be called one or more times. Declaring a function involves specifying the instructions that the function will contain. When a function is called, it executes those instructions. Functions are fundamental to computer programming in general, and they play a central role in JS++.

Note: This tutorial does not cover external functions in JS++. An external function is declared with the function keyword and returns an external type. We will examine external functions and external types in Chapter 9. (To preview, an external type is one which isn’t a JS++ type; usually, these will be JavaScript types.) This tutorial examines internal JS++ functions. Internal functions are not declared using the function keyword, and can return any type.

Declaring and calling functions

Before we can use a function to do anything, we have to declare it. So let’s start by looking at how functions are declared. Make a new folder and name it "Functions". Then make a new file and name it "Functions.jspp". Write in the following code:

            external $;

            string getFavoriteAnimalString(string animal) {
                return "My favorite animal is the " + animal;
            }
            

Save Functions.jspp to your Functions folder. The code we have written declares a function named getFavoriteAnimalString. This name is appropriate, because the function’s purpose is to return a string which states one’s favourite animal. That task is accomplished by the return statement in the function’s body (the part within the curly braces): the return statement evaluates the expression to the right of the return keyword, and then sends the evaluated expression back to the function’s caller (where it might be assigned to a variable, for example). Since the purpose of getFavoriteAnimalString is to return a string, we can say that the function’s return type is string, and we specify this by writing string to left of the function’s name.

Just as the output of getFavoriteAnimalString will be a string, it also takes a string input. To compose the string which reports one’s favourite animal, the function needs to know which particular animal is one’s favourite. It receives this input information via the string parameter named animal, which we write inside the parentheses to the right of the function’s name. When at a later stage of our program we call getFavoriteAnimalString to get it to execute, we will pass a particular string into its input parameter: the particular string we pass it will be the function’s argument.

Note: The distinction between a function’s parameter(s) and its argument(s) can be confusing. To clarify, a parameter is a variable written when declaring a function. The parameter type specifies what type of input the function takes. An argument, by contrast, is the actual value passed to a function as input when the function is called. The argument becomes the value of the parameter variable.

Before we call getFavoriteAnimalString, let’s set up an HTML document which we will use to display the result. Make a second file named "Functions.html" and write in the following:

            <!DOCTYPE html>
            <title>Functions program</title>
            <body>
            <p id="content"></p>
            <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
            <script src="Functions.jspp.js"></script>
            </body>
            </html>
            

Save Functions.html to your Functions folder. Now go back to Functions.jspp and write in the following, below the code where you declared getFavoriteAnimalString:

            string favoriteAnimalString = getFavoriteAnimalString("cat");
            $("#content").text(favoriteAnimalString);
            

On the first of these new lines, we call getFavoriteAnimalString, passing it the string "cat" as its argument. This function call returns the string "My favorite animal is the cat", and we assign this string to the variable favoriteAnimalString. On the second line, we use jQuery to select the "content" element of Functions.html and to set its text to the value of favoriteAnimalString. Compile Functions.jspp and then open Functions.html in a browser. If everything has worked, your document should display "My favorite animal is the cat".

Returning from a function

In our example, getFavoriteAnimalString returns a string. In general, however, a JS++ function can return any valid type, so long as the value returned belongs to the return type specified to the left of the function’s name in the declaration.

A function cannot have more than one return type, but it need not return anything at all. If a function does not return anything, it should be declared with the void keyword:

            void displayFavoriteAnimalString(string animal) {
                string favoriteAnimalString = "My favorite animal is the " + animal;
                $("#content").text(favoriteAnimalString);
            }
            

A void function can be declared without using a return statement (as in the example above), or it can be declared with the statement return; which doesn’t evaluate or return any expression.

When a function executes a return statement, it exits immediately. This means that any code written after a return statement will not execute.

Parameters

Functions can take zero, one, or multiple parameters. If a function takes multiple parameters, then those parameters can be of the same type or different types:

            void displayFavoriteAnimalIfLucky(string animal, int number) {
                string favoriteAnimalString = "My favorite animal is the " + animal;
                if(number == 7) {
                    $("#content").text(favoriteAnimalString);
                }
            }
            

Note: A function can also take a variadic parameter, which allows the function to take infinitely many arguments for that single parameter. A full understanding of variadic parameters requires an understanding of arrays, however, which won’t be covered until the next tutorial. We will therefore postpone discussion of variadic parameters until then.

Recursive functions

A recursive function is one that may call itself during its execution. Here is a well-known example of a recursive function:

            int factorial (int input) {
                if (input <= 1) {
                    return input;
                } else {
                    return input * factorial(input - 1);
                }
            }
            

The purpose of factorial is to calculate and return the factorial of the input parameter. For example, if we call factorial with an input of 5, it will return 120.

factorial illustrates a general structure that is common to many recursive functions. The function handles two sorts of cases differently, depending on the value of the input argument. In the base case, the value of the argument means that the function’s task can be accomplished easily, with little or no further work required. The function therefore returns without any need to call itself. In the recursive case, by contrast, significant further work is required. To accomplish this, the function in some way simplifies or reduces that further work, which involves calling itself with a modified input value. The modified input value will be closer to the value needed to qualify for a base case.

The base case for factorial comes when the input argument is less than or equal to 1. In this case, the function simply returns input. If input is greater than 1, by contrast, the functions returns input * factorial(input - 1). Thus factorial will repeatedly call itself, with the value of input decreasing by 1 with each recursive call. When factorial calls itself with an input value of 1, that particular recursive call returns, which then enables each of the previous recursive calls to return.

Recursive functions should be used with care. In particular, it is important to ensure that with each recursive call, the value of the input argument moves closer to that needed for the base case. If you don’t do this, there is a danger that you may create infinite recursion: this will cause a runtime error. In addition, it is often more efficient to use an iterative function (i.e. one which uses a loop) rather than recursion. When there is a benefit to using recursion, it usually consists in making one’s code easier to read, rather than increased computational efficiency.

Overloading

JS++ allows functions to be overloaded. Overloading consists in declaring two functions with the same name, but with different parameter lists. For example, we might overload a function named displayFavoriteAnimalString as follows:

            void displayFavoriteAnimalString(string animal) {
                string favoriteAnimalString = "My favorite animal is the " + animal;
                $("#content").text(favoriteAnimalString);
            }
            void displayFavoriteAnimalString(string firstAnimal, string secondAnimal) {
                string favoriteAnimalString = "My favorite animals include the " + firstAnimal + " and the " + secondAnimal;
                $("#content").text(favoriteAnimalString);
            }
            

The compiler allows you to declare two functions with the same name in this way, because of the difference in their parameter lists: the first function takes a single string parameter, whereas the second function takes two. This difference means that when you call one of the two functions, there is no ambiguity as to which is meant: if you supply one string argument then it must be the first function, and if you supply two string arguments then it must be the second.

In the example given, the two overloaded functions have the same return type: void. This isn’t required, however. So long as overloaded functions have different parameter lists, their return types can either be the same or different. You cannot, however, overload functions with the same parameter lists and different return types: this would lead to ambiguity about which function was meant by a caller, so the compiler won’t allow it.

Overloading can make good sense when the overloaded functions perform conceptually similar roles, where this similarity should be obvious from the perspective of the caller. Overloading should not be used where the overloaded functions perform conceptually different roles, since this will make your code harder to understand. One particular technique to avoid if possible is giving overloaded functions different return types: this isn’t considered good coding style.

Callbacks and function expressions

Consider the following code:

            external $;
            int(int, int) processNumbers = int(int a, int b) {
                return a + b;
            };
            

If you look carefully at this syntax (and do take note of the trailing semi-colon!), you will see that it isn’t the normal syntax of a function declaration. Rather, what we have here is a variable assignment. The variable is named processNumbers, and its type is specified by the code to the left of the name: int(int, int). This is a callback type. A variable of this type can take a function as its value. However, the range of functions which the variable can take is restricted to those whose parameters and return type match those specified by the callback type. So given that processNumbers has the callback type int(int, int), a function can be assigned to processNumbers only if it takes two int parameters and returns an int.

The code to the right of the "=" sign assigns a function expression to process numbers. A function expression differs from a function declaration in that it evaluates to a value (the function expressed). This means that a function expression can be used (as here) in a variable assignment, or passed as an argument to another function, or returned from another function.

The function assigned to processNumbers is an addition function. It adds the two int arguments together and returns the result. The assignment is fine, since the addition function has the parameters and return type specified by the variable’s callback type: it takes two int parameters and returns an int. Now we can call processNumbers:

            int result = processNumbers(3, 4);
            $("#content").text(result);
            

Later on in our program, however, we might decide to assign a different function to processNumbers:

            processNumbers = int(int a, int b) {
                return a * b;
            };
            

This assignment is just as valid as the previous one, since the multiplication function assigned also has the correct parameters and return type: it takes two int parameters and returns an int. If we call processNumbers after assigning this new function to it, the result will differ from the one returned by our earlier call.

Modules

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

Modules provide a way to organize code and divide an application into smaller parts. For example, a personal computer can be divided into keyboard, mouse, and monitor "modules" that can be separately connected.

Ideally, in modular design, we want our modules to be independently "re-usable." A PS/2 keyboard can be connected to any machine that has a PS/2 port because it's not tailored for an individual machine. Likewise, in software, your company or organization might have multiple applications that require authentication. Rather than re-writing the login and authentication code repeatedly for each individual application, you might want to expose the authentication functionality via a single module instead.

Modules in JS++ can be declared using the 'module' keyword.

Create a folder named 'Calculator'. Create a file inside the folder named 'Calculator.jspp' and add the following code:

        module Calculator
        {
            int add(int a, int b) {
                return a + b;
            }
            int subtract(int a, int b) {
                return a - b;
            }
        }
        

However, we can't just execute module code in the same file. JS++ encourages "modular design" and requires your modules to be separated from your main program logic.

Main File

The "main file" is the application entry point. In other words, you are telling the JS++ compiler, "My application starts here." JS++ allows only one application entry point. Let’s start with an example; create a file named 'main.jspp' that will import our 'Calculator' module with the following code:

            import Calculator;
            external $;

            int result = Calculator.add(1, 1);
            $(".display-result").text(result);
            

There's a lot going on here so let's break it down. In earlier chapters, we imported JavaScript libraries using the 'external' keyword. We still import jQuery (a JavaScript library) using the 'external' keyword in our above code. However, to import JS++ libraries (defined with the 'module' keyword), we need to use the 'import' keyword. This is an important distinction because it allows us to isolate unsafe JavaScript code.

The 'import' statement expects the full module name. In our simple example, the full module name is just 'Calculator'. JS++ knows what to do from there.

Next, we use one of the methods defined in the 'Calculator' module: the 'add' method. We simply add 1 + 1 and store the result in the 'result' variable. We then use jQuery to display the result of our calculation.

Let's create a calculator.html file for displaying our result:

            <!DOCTYPE html>
            <head>
                <title>Calculator</title>
            </head>
            <body>
            <div class="display-result"></div>

            <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
            <script src="app.jspp.js"></script>
            </body>
            </html>
            

Compile both the Calculator.jspp and main.jspp files. For Windows, this is as easy as selecting both files, right-clicking one of the files, and choosing "Compile with JS++". For Mac and Linux, use the following command:

> js++ Calculator.jspp main.jspp

An 'app.jspp.js' file should be generated by JS++.

The order of the input files does not matter. JS++ will automatically resolve the order that the files need to be compiled.

Open index.html and you should see the result: 2.

Nested Modules and Partial Qualification

In JS++, we can declare nested modules to further organize our code. There are two ways to do this:

            module MyApplication
            {
                module Calculator
                {
                    // ...
                }
            }
            
or:
            module MyApplication.Calculator
            {
                // ...
            }
            

Let's change Calculator.jspp so that the 'Calculator' module becomes exclusive to 'MyApplication' to organize our code:

            module MyApplication.Calculator
            {
                int add(int a, int b) {
                    return a + b;
                }
                int subtract(int a, int b) {
                    return a - b;
                }
            }
            

Now that we've changed our module structure, we have to change our main.jspp import statement to reflect this. However, we're going to add a twist to save ourselves some typing:

            import MyApplication.Calculator; 
            external $; 
             
            int result = add(1, 1); 
            $(".display-result").text(result);
            

Compile the files and open index.html in your web browser. You should notice the same result: 2.

Did you notice the added twist?

Instead of calling Calculator.add, we simply called the addition function via 'add'. All of the following are correct ways of calling the 'add' function:

            add(1, 1); 
            Calculator.add(1, 1); 
            MyApplication.Calculator.add(1, 1);
            

The first two lines are known as "partial qualification." The third and last line is known as "full qualification." A fully-qualified name is the "full path, " and a partially-qualified name is a "relative path."

JS++ allows you to use such relative paths via partially-qualified names to keep your code terse. However, the more you qualify a name, the easier your code will be to read and follow. The choice of code style is up to you.

Types in JavaScript

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

In this chapter, we're going to explore JavaScript programming styles and how developers worked with types in JavaScript (rather than JS++). This chapter will help you understand the next chapters which explain the JS++ type system in detail.

In this tutorial, we will be using the Google Chrome web browser. Click here to download Google Chrome if you don't already have it.

In order to execute JavaScript code, we'll be using the Chrome Developer Tools console. Open Chrome and hit the Ctrl + Shift + J key combination and choose the "Console" tab.

Copy and paste the following code into your console and press enter to execute it:

        var message;
        message = "This is a test.";
        if (Math.random() > 0.5) {
            message = 123;
        }
        console.log(message);
        

Hit your "up arrow" and hit "enter" to evaluate the code more than once. Try evaluating the code a few times.

Chrome Console Example

Notice how the data type in the above code changes from a string to a number. However, it only changes to a number if a randomly-generated number is greater than 0.5. Therefore, the data type of the variable 'message' can be different each time the script is executed. This was a major problem in JavaScript. For example, the following JavaScript code is unsafe:

        function lowercaseCompare(a, b) {
            return a.toLowerCase() == b.toLowerCase();
        }
        

The reason is because toLowerCase() is a method that's only available to JavaScript strings. Let's execute the following JavaScript code in the Chrome console:

        function lowercaseCompare(a, b) {
            return a.toLowerCase() == b.toLowerCase();
        }

        console.log("First message.");
        lowercaseCompare("10", 10); // Crashes with 'TypeError'
        console.log("Second message."); // Never executes.
        

Notice how the script will crash with a TypeError. The second message never gets logged. The key takeaway is that the code crashed because toLowerCase() is not a method available for numbers, but the function was called with a string ("10") and a number (10). The number argument was not a valid argument for the 'lowercaseCompare' function. If you change the function call, you will observe that the program no longer crashes:

        // Change this:
        // lowercaseCompare("10", 10); // Crashes with 'TypeError'
        // to:
        lowercaseCompare("10", "10");
        

Developers worked around these problems in JavaScript by checking the types first. This is the safer way to rewrite the above 'lowercaseCompare' function in JavaScript:

        function lowercaseCompare(a, b) {
            if (typeof a != "string" || typeof b != "string") {
                return false;
            }

            return a.toLowerCase() == b.toLowerCase();
        }
        

We check the types using 'typeof', and, if we receive invalid argument types, we return a default value. However, for larger programs, this can result in a lot of extra code and there may not always be an applicable default value.

Unforgiving Errors in JavaScript

In the previous example, we explored one type of unforgiving error in JavaScript: a TypeError that causes script execution to end. There are many other types of errors that JS++ prevents, but, for now, we'll only look at one other category of errors: ReferenceErrors. What's wrong with the next bit of JavaScript code?

            var message = "This is a test.";
            console.log(messag);
            

Try executing the above code in your console. Once again, nothing gets logged. Instead, you get a ReferenceError. This is because there's a typo in the above code. If we fix the typo, the code succeeds:

            var message = "This is a test.";
            console.log(message);
            

JavaScript can fail on typos! TypeErrors and ReferenceErrors don't happen in JS++. We classify TypeErrors and ReferenceErrors as "unforgiving" errors because they can cause JavaScript script execution to halt. However, there's another type of error in JavaScript that's a little more dangerous because they're "silent."

Forgiving "Silent" Errors in JavaScript

There is a class of "silent" errors in JavaScript that can silently continue to propagate through your program. We call these "forgiving" errors because they don't stop script execution, but, despite the innocuous name, we can consider them more dangerous than unforgiving errors because they continue to propagate.

Consider the following JavaScript function:

function subtract(a, b) { return a - b; }

This function might seem straightforward on the surface, but – as the script gets more complex – when variables change and depend on other values spanning thousands of lines of code, you might end up accidentally subtracting a variable that ends up being a number from a variable that ends up being a string. If you attempt such a call, you will get NaN (Not a Number).

Evaluate the following code in your console:

            function subtract(a, b) { return a - b; }
            subtract("a", 1);
            

Observe the resulting NaN (Not a Number) value. It doesn't crash your application so we call it a forgiving error, but the error value will propagate throughout the rest of your program so your program continues to silently run with errors. For example, subsequent calculations might depend on the value returned from the 'subtract' function. Let's try additional arithmetic operations to observe:

            function subtract(a, b) { return a - b; }
            var result = subtract("a", 1); // NaN
            console.log(result);
            result += 10; // Add 10 to NaN
            console.log(result);
            

No crash and no error reports. It just silently continues to run with the error value.

You won't be able to run the following code, but here's an illustration of how such error values might propagate through your application in a potential real-world scenario, a shopping cart backend:

            var total = 0;
            total += totalCartItems();
            while ((removedPrice = removedFromCart()) != null) {
                total = subtract(total, removedPrice);
            }
            total += tax();
            total += shipping();
            

In the example above, our shopping cart can end up with a NaN (Not a Number) value – resulting in lost sales for the business that can be difficult to detect because there were no explicit errors.

JavaScript Intuition

JS++ was designed based on extensive JavaScript development experience – not just for large, complex applications but anywhere JavaScript could be used – scripts and macros for Windows Script Host to legacy programs based on ActiveX and the like which are still prevalent in some corporate environments. In short, JS++ will work anywhere that JavaScript is expected – from the basic to the complex to the arcane.

One important observation relevant to JS++ is that most JavaScript programs are already well-typed (but not "perfectly" typed). Recall the "unsafe" and "safe" versions of the JavaScript 'lowercaseCompare' function:

            // Unsafe:
            function lowercaseCompare(a, b) {
                return a.toLowerCase() == b.toLowerCase();
            }
            // Safe: 
            function lowercaseCompare(a, b) {
                if (typeof a != "string" || typeof b != "string") {
                    return false;
                }

                return a.toLowerCase() == b.toLowerCase();
            }
            

The safe version is much more tedious, and – in practice – most JavaScript developers will write most of their functions the unsafe way. The reason is because, by looking at the function body, we know the expected parameter types are strings because both parameters use the 'toLowerCase' method only available to strings. In other words, in JavaScript, we have an intuition about the types just by looking at the code.

Consider the following variables and guess their types:

            var employeeAge;
            var employeeName;
            var isEmployed;
            

employeeAge makes sense as a number, employeeName makes sense as a string, and isEmployed makes sense as a Boolean.

Now try guessing the expected parameter types for the following functions:

            function multiply(a, b) { return a * b; }
            function log(message) { console.log("MESSAGE: " + message); }
            

The function 'multiply' makes most sense if you supply numeric arguments to the 'a' and 'b' parameters. Furthermore, the 'log' function is most correct with strings.

JavaScript Forced Conversions ("Type Coercion")

Sometimes, instead of checking the type using 'typeof', JavaScript programmers will instead force a conversion of the argument to the data type they need (especially if intuition might fail). This technique is an instance of type coercion and results in code that is more fault tolerant because it won't exit with an exception if the data type of the argument provided is incorrect.

Once again, let's see how we can change our 'lowercaseCompare' example using this idea:

            // Unsafe:
            function lowercaseCompare(a, b) {
                return a.toLowerCase() == b.toLowerCase();
            }
            // Safer: 
            function lowercaseCompare(a, b) {
                a = a.toString();
                b = b.toString();

                return a.toLowerCase() == b.toLowerCase();
            }
            

In the re-written version of the 'lowercaseCompare' function, we are "forcing" the 'a' and 'b' arguments to be converted to a string. This allows us to safely call the 'toLowerCase' method without a crash. Now, if the 'lowercaseCompare' function is called, we get the following results:

            lowercaseCompare("abc", "abc") // true
            lowercaseCompare("abc", 10) // false
            lowercaseCompare("10", "10") // true
            lowercaseCompare("10", 10) // true
            

However, the astute observer will notice the new version of 'lowercaseCompare' is marked "safer" rather than "safe."

Why?

toString is not the most correct way to force a conversion to a string. (It's also not the fastest due to runtime method lookups, but imagine having to consider all these details while writing one line of code? This is how programming for the web used to be before JS++.)

One example is if we try to call 'lowercaseCompare' with a variable we forgot to initialize, it will crash again if we use 'toString'. Let's try it:

            function lowercaseCompare(a, b) {
                a = a.toString();
                b = b.toString();

                return a.toLowerCase() == b.toLowerCase();
            }
            var a, b; // uninitialized variables
            var result = lowercaseCompare(a, b);
            console.log(result); // Never executes
            

No, instead, the most correct way to perform type coercion to string would be like this:

            // Finally safe: 
            function lowercaseCompare(a, b) {
                a += ""; // correct type coercion
                b += ""; // correct type coercion

                return a.toLowerCase() == b.toLowerCase();
            }
            var a, b;
            var result = lowercaseCompare(a, b);
            console.log(result);
            

There's just one problem left with the correct code: it becomes unreadable. What would your code look like if you had to insert += "" everywhere that you wish to express the intent that you want string data?

'lowercaseCompare' in JS++

Now that was a lot to digest! Writing good code in JavaScript is hard. Imagine having to take into account all these considerations when writing a small bit of code in JavaScript: safety, performance, code readability, unforgiving errors, silent errors, correctness, and more. This actually only scratches the surface of JavaScript corner cases, but it provides us enough information to begin understanding types in JS++.

However, if we write our code in JS++, JS++ actually handles all these considerations for us. This means you can write code that is readable, but the JS++ compiler will handle generating code that is fast, safe, and correct.

Before we move on to the next chapter – which explains the JS++ type system in detail – let's try to rewrite the 'lowercaseCompare' code in JS++. We'll start with code that is intentionally incorrect to show you how JS++ catches such errors early and show you how to fix them. Create a 'test.jspp' file and type in the following code:

            import System;

            function lowercaseCompare(string a, string b) {
                return a.toLowerCase() == b.toLowerCase();
            }

            Console.log("First message.");
            lowercaseCompare("10", 10);
            Console.log("Second message.");
            

Try compiling the file. It won't work. JS++ found the error early:

[ ERROR ] JSPPE5024: No overload for `lowercaseCompare' matching signature `lowercaseCompare(string, int)' at line 8 char 0 at test.jspp

It tells you exactly the line where the error occurred so you can fix it – before your users, visitors, or customers get a chance to encounter it. Let's fix the offending line, which JS++ told us was on Line 8:

            // lowercaseCompare("10", 10);
            // becomes:
            lowercaseCompare("10", "10");
            

Run the code after fixing the offending line. In Windows, right-click the file and choose "Execute with JS++". In Mac or Linux, run the following command in your terminal:

> js++ --execute test.jspp

You'll see both messages logged successfully.

In the next chapter, we'll explore the JS++ type system and "type guarantees" by example.

The JS++ Type System

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

RGBtoHex: Using JavaScript from JS++

We're going to create two files, a JavaScript file and a JS++ file, to introduce how they interact together. We're going to use the classic 'rgbToHex' example to understand JS++ type guarantees.

First, create a file named rgbtohex.js (JavaScript) and enter the following code:

(Don't worry about trying to understand this JavaScript code. We're only going to use it as an example.)

            function rgbToHex(red, green, blue) {
                if (typeof red   !==  "number") throw new TypeError("Expected numeric 'red' value");
                if (typeof green !==  "number") throw new TypeError("Expected numeric 'green' value");
                if (typeof blue  !==  "number") throw new TypeError("Expected numeric 'blue' value");

                if (red < 0   || red > 255)     throw new RangeError("Expected 'red' value between 0 and 255 (inclusive)");
                if (green < 0 || green > 255)   throw new RangeError("Expected 'green' value between 0 and 255 (inclusive)");
                if (blue < 0  || blue > 255)    throw new RangeError("Expected 'blue' value between 0 and 255 (inclusive)");

                var r = red.toString(16);
                var g = green.toString(16);
                var b = blue.toString(16);

                while (r.length < 2) r = "0" + r;
                while (g.length < 2) g = "0" + g;
                while (b.length < 2) b = "0" + b;

                return "#" + r + g + b;
            }
            

Save the above JavaScript code to rgbtohex.js and create a new main.jspp file:

            external alert;
            external rgbToHex;

            alert(rgbToHex(255, 255, 255));
            

We start by declaring 'alert' as 'external'. 'alert' is actually a function native to web browsers (via the "DOM API") that allows us to show message boxes. Next, we declare our custom JavaScript function we just wrote ('rgbToHex') as 'external'. This allows us to use the function from JS++.

Compile main.jspp. Now create an index.html file:

            <!DOCTYPE html>
            <head>
                <title>RGB to Hex Conversion</title>
            </head>
            <body>
            <script src="rgbtohex.js"></script>
            <script src="main.jspp.js"></script>
            </body>
            </html>
            

Make sure the <script> tag for the JavaScript dependency (rgbtohex.js) is written before the JS++ compiled main.jspp.js file's <script> tag.

Open index.html in your web browser. You should see a message box like this:

RGBtoHex Screenshot

The resulting value is "#ffffff", which is the equivalent hexadecimal color code for the RGB value of (255, 255, 255), the values we inputted in main.jspp.

We've just successfully used a custom JavaScript function we wrote from JS++.

Type Guarantees

"Type guarantees" are a unique feature of JS++ that mean your types are guaranteed to be correct during compile-time analysis and runtime code execution even when you're polluting your JS++ code with untyped JavaScript code. It's the closest thing you'll find to the type safety featured in safer languages that don't have to deal with large collections of untyped code.

When you use keywords like 'external', 'var', or 'function', you'll respectively get imports, variables, and functions that are "external types" and are untyped and unchecked. In other words, you're just writing JavaScript inside of JS++. However, when you declare variables and functions with a JS++ type such as 'int', 'string', 'bool', 'short', or 'unsigned int', these are known as "internal types" and are guaranteed to be correct.

When "external types" cross into the territory of "internal types," a runtime conversion is generated:

            var x = 123;
            int y = x; // 'x' is converted to 'int', 'y' is therefore guaranteed to be 'int'
            

Due to the conversion, we are guaranteed to always be dealing with types correctly. We'll continue to explore how this concept works in practice throughout this chapter and the next, but, first, let's see how this applies to our RGB to Hex Converter.

Key Concept

In JS++, the key concept to understand is that JS++ splits data types into "internal" types and "external" types. Internal data types are the JS++ data types: int, string, bool, unsigned int, array types, dictionaries, and user-defined types (which we'll cover in Chapter 12). External types are the data types of JavaScript.

The JS++ type system is essentially the internal data types, the external data types, and the conversions between them. As we explored in the JavaScript chapter, type conversion is actually the safest and most fault-tolerant way to deal with types in JavaScript, and JS++ builds on this.

RGB Values

The RGB color model defines three color values: red, blue, and green. These color values are numeric and must fit within the range 0-255. JS++ actually happens to have a data type that exactly fits the specification of being numeric and guaranteeing numbers to be in the 0-255 range: the 'byte' data type.

Due to type guarantees, when we declare the data type in JS++, it can change the runtime behavior of our program – much the same way as they would in C, C++, Java, C#, and many other statically-typed programming languages. Therefore, if we define RGB as expecting byte values that range from 0 to 255, we are guaranteed for these values to be numeric and range between 0 to 255 during compile-time analysis and runtime application execution.

For example, during compile-time analysis and error checking, the compiler will give you an error if you accidentally try to pass an 'int' where a 'byte' was expected since 'int' allows numbers outside the 0 to 255 range.

Likewise, at runtime when your application is running, variables that you declared as a 'byte' are guaranteed to never be 256. This means we can never get invalid RGB values. (For developers coming from backgrounds such as C or C++, you're also guaranteed to never have an 'unsigned int' be -1 at runtime because unsigned – and signed – overflow results in integer wrapping.)

Examining the Untyped JavaScript

RGB values must be within the 0 to 255 range. Since JavaScript lacks data types, we have to manually perform these checks. Let's inspect how we handle this in our 'rgbToHex' JavaScript function.

The first three lines of our 'rgbToHex' JavaScript function check for numbers:

            if (typeof red   !==  "number") throw new TypeError("Expected numeric 'red' value");
            if (typeof green !==  "number") throw new TypeError("Expected numeric 'green' value");
            if (typeof blue  !==  "number") throw new TypeError("Expected numeric 'blue' value");
            

If we did not provide numbers as arguments, we generate a runtime error with the 'throw' statement.

The next three lines check that these numbers fit within the 0 to 255 range:

            if (red < 0   || red > 255)     throw new RangeError("Expected 'red' value between 0 and 255 (inclusive)");
            if (green < 0 || green > 255)   throw new RangeError("Expected 'green' value between 0 and 255 (inclusive)");
            if (blue < 0  || blue > 255)    throw new RangeError("Expected 'blue' value between 0 and 255 (inclusive)");
            

Once again, if the numbers are not in range, we throw a runtime error using the 'throw' statement.

However, why settle for runtime errors during application execution? In JS++, these errors can be checked without running the program — at compile time.

Using JavaScript More Safely

You can use JavaScript more safely from JS++ than you can from JavaScript itself.

Let's start by modifying our main.jspp code to explicitly use the 'byte' data type:

            external alert;
            external rgbToHex;

            byte red = 255;
            byte green = 255;
            byte blue = 255;
            alert(rgbToHex(red, green, blue));
            

Compile main.jspp and open index.html. The result should be exactly the same: a message box will pop up containing "#ffffff". However, there's a difference this time: you're guaranteed to only be able to send whole number values ranging from 0 to 255.

Remember all those checks in the JavaScript function to make sure we received acceptable RGB input values? If incorrect values were provided, the script will stop application execution by throwing exceptions. All of these potential errors have been wiped out by using JS++ and declaring types. These errors have been wiped out despite the fact that we haven't modified any of the original JavaScript code. The runtime errors are still present in the JavaScript code, but they will never execute because the input values we provide will always be correct.

Try changing one of the 'red', 'green', or 'blue' variables to a number outside the 0 to 255 range:

            external alert;
            external rgbToHex;

            byte red = -1;
            byte green = 255;
            byte blue = 255;
            alert(rgbToHex(red, green, blue));
            

Now try to compile the modified main.jspp file. You'll get an error:

[ ERROR ] JSPPE5013: Computed value `-1' is out of range for type `byte' at line 4 char 11 at main.jspp

We can build on this and re-write the entire 'rgbToHex' function in JS++ instead of JavaScript to improve type safety while removing all the runtime checks and errors.

Move rgbToHex to JS++

First, let's stop importing the JavaScript 'rgbToHex' function by removing the 'external' statement that imports it. Our main.jspp file should now just look like this:

            external alert;

            alert(rgbToHex(255, 255, 255));
            

Don't try to compile right now. We'll compile once we've moved all the JavaScript code.

The 'rgbToHex' JavaScript function depends on 'TypeError' (native to JavaScript) and 'RangeError' (also native to JavaScript). Let's import these:

            external alert;
            external TypeError, RangeError;

            alert(rgbToHex(255, 255, 255));
            

Finally, we can just copy and paste the code from rgbToHex.js (the JavaScript file) into main.jspp (the JS++ file):

            external alert;
            external TypeError, RangeError;

            function rgbToHex(red, green, blue) {
                if (typeof red   !==  "number") throw new TypeError("Expected numeric 'red' value");
                if (typeof green !==  "number") throw new TypeError("Expected numeric 'green' value");
                if (typeof blue  !==  "number") throw new TypeError("Expected numeric 'blue' value");
             
                if (red < 0   || red > 255)     throw new RangeError("Expected 'red' value between 0 and 255 (inclusive)");
                if (green < 0 || green > 255)   throw new RangeError("Expected 'green' value between 0 and 255 (inclusive)");
                if (blue < 0  || blue > 255)    throw new RangeError("Expected 'blue' value between 0 and 255 (inclusive)");
             
                var r = red.toString(16);
                var g = green.toString(16);
                var b = blue.toString(16);
             
                while (r.length < 2) r = "0" + r;
                while (g.length < 2) g = "0" + g;
                while (b.length < 2) b = "0" + b;
             
                return "#" + r + g + b;
            }

            alert(rgbToHex(255, 255, 255));
            

Now we can compile the code. It should compile successfully. Open index.html in your web browser, and you should notice the result is still a message box displaying "#ffffff".

We just copied a large chunk of JavaScript code directly into JS++ and it worked. This is because JS++ is a superset of JavaScript; in other words, it's just JavaScript with more features.

However, we still need to convert this "untyped" JavaScript code that we copied and pasted into JS++ to take advantage of JS++ type guarantees. Otherwise, we're just writing regular JavaScript inside JS++.

Converting the "Untyped" JavaScript into "Typed" JS++

We'll start converting our JavaScript 'rgbToHex' function into JS++ by removing all the runtime checks and errors. You won't be needing them anymore.

Your main.jspp file should now look like this:

            external alert;

            function rgbToHex(red, green, blue) {
                var r = red.toString(16);
                var g = green.toString(16);
                var b = blue.toString(16);
             
                while (r.length < 2) r = "0" + r;
                while (g.length < 2) g = "0" + g;
                while (b.length < 2) b = "0" + b;
             
                return "#" + r + g + b;
            }

            alert(rgbToHex(255, 255, 255));
            

By removing the runtime checks and errors, we can actually improve potential performance. An obvious observation is that there are fewer instructions to process overall. However, by removing all the if statements, we improve instruction-level parallelism at the hardware (CPU) level and decrease the opportunities for branch misprediction. (These optimizations may or may not apply due to all the additional layers of abstraction in browser scripting. For now, it will suffice to know that we've decreased the overall number of operations.)

Since we removed the runtime checks and errors, our code is now completely unchecked! Try calling 'rgbToHex' with an invalid value like 256. You'll observe that it's allowed. Let's fix that.

Add 'byte' in front of each parameter to restrict their data types:

            external alert;

            function rgbToHex(byte red, byte green, byte blue) {
                var r = red.toString(16);
                var g = green.toString(16);
                var b = blue.toString(16);
             
                while (r.length < 2) r = "0" + r;
                while (g.length < 2) g = "0" + g;
                while (b.length < 2) b = "0" + b;
             
                return "#" + r + g + b;
            }

            alert(rgbToHex(255, 255, 255));
            

Compile main.jspp and open index.html. As usual, you'll see a message box displaying "#ffffff".

Now try calling the 'rgbToHex' function with an invalid value like -1 or 256 again. You will no longer be able to compile the code because the errors will be detected at compile time.

Add More Types

Our 'rgbToHex' function is still declared with the keyword 'function'. This is the JavaScript way of declaring a function, and it still leaves our function unsafe.

In JS++, it is best practice to always declare data types when possible. Since we always return a string value for our 'rgbToHex' function, we should restrict the return type to 'string'.

            external alert;

            string rgbToHex(byte red, byte green, byte blue) {
                var r = red.toString(16);
                var g = green.toString(16);
                var b = blue.toString(16);
             
                while (r.length < 2) r = "0" + r;
                while (g.length < 2) g = "0" + g;
                while (b.length < 2) b = "0" + b;
             
                return "#" + r + g + b;
            }

            alert(rgbToHex(255, 255, 255));
            

Now all 'return' statements inside the function must return an expression that evaluates to string data.

Last but not least, look at these statements:

            var r = red.toString(16);
            var g = green.toString(16);
            var b = blue.toString(16);
            

What methods are being called?

Remember, a lot of programming with types in JavaScript is based on intuition. (The JS++ type system builds on top of this intuition so programming in JS++ should feel like a natural progression for JavaScript developers.) In each of the above statements, 'toString(16)' is being called. In other words, we know we should expect string data. Let's change our 'var' to 'string' then:

            external alert;

            string rgbToHex(byte red, byte green, byte blue) {
                string r = red.toString(16);
                string g = green.toString(16);
                string b = blue.toString(16);
             
                while (r.length < 2) r = "0" + r;
                while (g.length < 2) g = "0" + g;
                while (b.length < 2) b = "0" + b;
             
                return "#" + r + g + b;
            }

            alert(rgbToHex(255, 255, 255));
            

Compile main.jspp. Delete the rgbtohex.js JavaScript file. Edit index.html to completely remove the reference to the JavaScript rgbtohex.js file. Your index.html code should now look like this:

            <!DOCTYPE html>
            <head>
                <title>RGB to Hex Conversion</title>
            </head>
            <body>
            <script src="main.jspp.js"></script>
            </body>
            </html>
            

Open index.html in your web browser. You should see a message box with "#ffffff". Congratulations! You've just changed a JavaScript function into JS++.

Other Considerations

As we learned in the previous chapter about JavaScript, we intuitively have a sense of the data type to expect.

However, there isn't always a compatible JS++ type for all JavaScript values. This can be illustrated with jQuery. For example, let's re-visit an example from Chapter 5 on loops:

            external $;

            for (int i = 0; i < 2; i++) {
                $("#content").append("i is now ", i, "; ");
            }
            

This is an interesting example because it covers a lot. First of all, what if we wanted to break up the jQuery method call so that the selection of #content (a page element with ID "content") is saved to a variable? There isn't a compatible JS++ type here, so we can just use 'var':

            external $;

            for (int i = 0; i < 2; i++) {
                var content = $("#content");
                content.append("i is now ", i, "; ");
            }
            

In theory, it's better to have zero unsafe code. However, in practice, 'external', 'var', and 'function' are necessary for compatibility with JavaScript. In other words, external types are needed. Ideally, we would never use externals in "perfect JS++ code, " but real-world programming is almost never ideal.

The astute observer may have also noticed a conversion in the opposite direction: from internal to external. We declared the 'for' loop counter variable 'i' as an 'int', an internal JS++ type. However, when we pass it as an argument to jQuery, it gets converted to 'external':

content.append("i is now ", i, "; ");

By default, the "primitive types" (such as 'int', 'string', 'bool', 'unsigned int', etc.) have implicit default conversions defined to and from 'external'. This is because JavaScript has natural compatible data types for the internal JS++ primitive types. Thus, the conversion is also natural. It gets more complex with user-defined types and user-defined conversions, but we'll cover those in later chapters.

It's important to understand the difference between a forward guarantee and a backwards guarantee. In a forward guarantee, we don't worry about the past and focus on the future. For instance, consider a simple wrapper for the browser's message box function ('alert'):

            external alert;

            void messageBox(string message) {
                alert(message);
            }
            

In the above code, it doesn't matter if you call 'messageBox' with unsafe code because the 'message' variable is guaranteed to be 'string' going forward for all logic inside the 'messageBox' function due to type guarantees.

Final Note

Why are JS++ type guarantees necessary? Because, with unsafe JavaScript, even large websites with resources, like GoDaddy, can have broken checkouts resulting in lost sales from a single TypeError:

GoDaddy TypeError

In the above, the "Continue" button never works so the shopping cart checkout cannot be finished.

Curiously, the checkout failure comes from the same 'toLowerCase' method that we explored in Chapter 8. Since JS++ is the only sound, gradually-typed programming language for JavaScript, type guarantees mean more than just adding "types" to JavaScript. It means the types are guaranteed to be correct when you declare them, and there are no edge cases that can result in runtime failures (unlike attempts to add data types by Microsoft and Facebook).

Don't be the one to break critical code because someone told you to write the code in JavaScript instead. You need more than types and type checking, you need type guarantees.

Collections

Charles Kozeny-PellingBy Charles Kozeny-Pelling

Charles Kozeny-Pelling is a graduate of the University of Oxford

In the course of a writing a computer program, you will often need to group multiple elements together into a collection of some form. JS++ provides two sorts of collections to help you in these contexts: arrays and dictionaries. They will be the focus of this tutorial.

Arrays

We will begin with arrays. Make a new folder named Collections, and then make a new file named "Collections.jspp". Write in the following code:

string[] friendsArray = ["Anna", "Betty", "Chris", "David"];

This code demonstrates a simple way to create a string array and populate it with four elements. The array is assigned to a variable named friendsArray, which belongs to the type string[]. Notice that the array variable makes specific reference to the type of element that the array can contain: string[] variables can only take arrays of string elements, not arrays of any other kind. If we tried to assign an int array to a string[] variable, our code would not compile.

The elements in an array are ordered and each is given a numerical index, starting at zero and increasing by 1 for each successive element. So in friendsArray, for example, "Anna" is given the index 0, "Betty" is given the index 1, and so on.

It’s useful for each element in an array to have an index, since it makes it possible to access the elements individually. To see how this works, let’s write some code which will display particular elements in friendsArray in an HTML document. Make a second file named "Collections.html" and write in the following:

            <!DOCTYPE html>
            <title>Collections program</title>
            <body>
            <p id="content"></p>
            <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
            <script src="Collections.jspp.js"></script>
            </body>
            </html>
            

Save Collections.html to your Collections folder. Now return to Collections.jspp and add two extra lines to the one you already have:

            external $;

            string[] friendsArray = ["Anna", "Betty", "Chris", "David"];
            $("#content").append(friendsArray[0] ?? "", " ", friendsArray[2] ?? "");
            

Look at the last line here, and in particular the expressions friendsArray[0] and friendsArray[2]. These expressions are used to access the array elements at index 0 and index 2 (the first and third elements of the array, given that the index numbering starts from zero). If you compile your code and open Collections.html in a browser, you will see that it displays "Anna Chris".

You'll also notice ?? "" after the array accesses. This will be covered in the next chapter, "Nullable and Existent Types", by Roger Poon. At this time, you only need to know that it is used for providing a default value (an empty string) in case the element is missing.

You can also use an array index to change the element at that index. For example, suppose that after creating our array, we want to change the second element to "Brian". We can do that by writing:

friendsArray[1] = "Brian";

Jagged arrays

JS++ also allows you to create so-called jagged arrays (also known as arrays of arrays): arrays that contain other arrays as elements. For example, we might want to create an array whose elements are string arrays. We could do that as follows:

string[][] jaggedArray = [["Anna", "Betty"], ["Chris", "David"]];

To access one of the inner arrays in jaggedArray, you would use the same syntax as before: jaggedArray[1] would return the array containing "Chris" and "David", for example. To access an element within one of the inner arrays, you would need to specify two indices: the first to indicate the inner array, and the second to indicate the specific element in that inner array. For example, jaggedArray[1][0] would return "Chris", while jaggedArray[0][1] would return "Betty".

Iterating over arrays

When using arrays, you will often want to iterate over their elements. There are two main ways to do this. The first is to use a regular for loop, of the sort we looked at in chapter 5:

            string[] friendsArray = ["Anna", "Betty", "Chris", "David"];
            for (int i = 0; i < friendsArray.length; ++i) {
                $("#content").append(friendsArray[i] ?? "", " ");
            }
            

Notice the condition clause of the for loop, which uses the expression friendsArray.length. This expression returns the number of elements in friendsArray, so it makes sense to use the expression to limit the number of iterations of the loop.

length is an example of a so-called "getter method". A method is a function that belongs to a particular class, and a getter is a particular kind of method which can be called without using parentheses. We’ll look in more detail at methods (getters and other kinds) and classes in chapters 12-27. The length method belongs to the Array<T> class, which makes it available to use on arrays. We’ll look at some of the other methods in the Array<T> class later in the tutorial.

Note: Methods in the Array<T> class are available to use on primitive arrays (of the sort we’re examining in this tutorial) due to a process known as autoboxing. Autoboxing happens when a primitive value is automatically converted into an instance of an associated "wrapper" class. In this context, when you use a method such as length on a primitive array, the primitive is autoboxed into an instance of the Array<T> wrapper class, which allows the method to be used. We’ll cover autoboxing in more detail in later chapters.

The other main way to iterate over an array is to use a foreach loop:

            string[] friendsArray = ["Anna", "Betty", "Chris", "David"];
            foreach (string name in friendsArray) {
                $("#content").append(name, " ");
            }
            

A foreach loop such as this is easier to write than a regular for loop, but it doesn’t give you access to each element’s index in the way that a regular for loop does. So when deciding which kind of loop to use, it will be important to consider whether you need access to the array indices.

Arrays and variadic parameters

In chapter 6, we noted that functions can have a variadic parameter, which allows the function to take infinitely many arguments for that single parameter. When the arguments are given to the function, they are stored as an array. Here is an example of a function with a variadic parameter.

            int add (...int numbers) {
                int total = 0;
                foreach (int number in numbers) {
                    total += number;
                }
                return total;
            }
            $("#content").append(add(1, 2, 3));
            

The add function is declared with the variadic parameter ...numbers. When the function is called, it is given the arguments 1, 2, and 3. These arguments are stored as an array named numbers, which then becomes available to be accessed in the function’s body. In this example, we loop over the elements in the array and then return their sum.

Note: A function can’t have more than one variadic parameter.

Array methods

Earlier in the tutorial, we looked at the length method in the Array<T> class, which returns the number of elements in an array. The Array<T> class contains many useful methods, in addition to length, and in this section we’ll look briefly at some of the central ones: indexOf, sort, push, and pop.

The indexOf method returns the first index of a search element, or -1 if the element could not be found in the array:

            string[] friendsArray = ["Anna", "Betty", "Chris", "David"];
            $("#content").append(friendsArray.indexOf("David"));
            

The sort method can be used to sort an array, if the elements in the array are sortable. (For more on sortability and sorting behaviors, see here: the sort method.) For example, we could sort an int array in numerically ascending order like this:

            int[] numbersArray = [7, 2, 9, 5];
            numbersArray.sort();
            foreach (int number in numbersArray) {
                $("#content").append(number, " ");
            }
            

To add one or more elements to the end of an array, you use the push method:

            int[] numbersArray = [7, 2, 9, 5];
            numbersArray.push(6, 5);
            foreach (int number in numbersArray) {
                $("#content").append(number, " ");
            }
            

To remove the last element in an array, you use the pop method:

            int[] numbersArray = [7, 2, 9, 5];
            numbersArray.pop();
            foreach (int number in numbersArray) {
                $("#content").append(number, " ");
            }
            

For a full list of methods in the Array<T> class, see here:

Methods in the Array<T> class

Dictionaries

Dictionaries are a different kind of collection from arrays. The main difference is that whereas arrays contain individual elements, dictionaries contain key-value pairs. Let’s take a look at some code which creates a JS++ dictionary. Before you write the new code, delete the code you already have in Collections.jspp. Now write in the following:

            import System;

            Dictionary<int> friendsAges = {"Anna": 47, "Betty": 28, "Chris": 35, "David": 54};
            

On the first line, you import the System module. We won’t cover the System module in detail in this chapter, but for now the key point is that this import statement lets you use the Dictionary<T>class, which is in the JS++ Standard Library. (We will cover the JS++ Standard Library in later chapters.) Without the import statement, the code that comes after would not compile.

With the import statement in place, however, your code does compile and it creates a dictionary that stores friends’ names and their ages in a key-value format. For each key-value pair, the key is the person’s name and the value is their age. The dictionary’s type is Dictionary<int>, since the value in each key-value pair is an int. We don’t need to specify the key type, in addition to the value type, since the key type in any dictionary must always be string.

Note: When writing the keys for a JS++ dictionary, it’s optional to use quotation marks. So for example, instead of writing Dictionary<int> dict = {"a": 1}; you could also write Dictionary<int> dict = {a: 1}; The compiler knows that your keys must be strings, so the quotation marks will be implicitly assumed if you leave them out.

A dictionary’s key-value pairs are not ordered and they are not assigned an index. To access a particular pair, you use its key. For example, if we wanted to display Anna’s age and Chris’s age in our HTML document, we could do so like this:

            import System;
            external $;
                
            Dictionary<int> friendsAges = {"Anna": 47, "Betty": 28, "Chris": 35, "David": 54};
            $("#content").append(friendsAges["Anna"] ?? 0, " ", friendsAges["Chris"] ?? 0);
            

The expression friendsAges["Anna"] returns the value corresponding to "Anna", and the expression friendsAges["Chris"] returns the value corresponding to "Chris". So if you compile this code and open Collections.html in a browser, your document will display "47 35".

You can also use a key to change the value of a key-value pair:

friendsAges["Anna"] = 48;

This changes the value corresponding to "Anna" to 48. It doesn’t insert a new key-value pair into friendsAges, because a dictionary cannot have two pairs with the same key. To insert a new pair into the dictionary, you would have to use a different key:

friendsAges["Emily"] = 39;

Iterating over dictionaries

It’s easy to iterate both over the keys and over the values of a dictionary. To iterate over the keys, you use a for...in loop:

            Dictionary<int> friendsAges = {"Anna": 47, "Betty": 28, "Chris": 35, "David": 54};
            for (string name in friendsAges) {
                $("#content").append(name, ": ", friendsAges[name] ?? "", ", ");
            }
            

The simplest way to iterate over a dictionary’s values, by contrast, is to use a foreach loop:

            Dictionary<int> friendsAges = {"Anna": 47, "Betty": 28, "Chris": 35, "David": 54};
            foreach (int age in friendsAges) {
                $("#content").append(age, " ");
            }
            

Dictionary methods

Earlier we saw that the Array<T> class contains many useful methods which you can use on arrays. Similarly, the Dictionary<T> class contains various methods which you can use on dictionaries. In this section, we will look briefly at three of the most important ones: length, contains, and remove.

The length method works exactly how you would expect it to, given the behavior of the corresponding method in the Array<T> class: it returns the number of key-value pairs in the dictionary:

            Dictionary<int> friendsAges = {"Anna": 47, "Betty": 28, "Chris": 35, "David": 54};
            $("#content").append(friendsAges.length);
            

The contains method can be used to check whether a dictionary contains a certain key:

            Dictionary<int> friendsAges = {"Anna": 47, "Betty": 28, "Chris": 35, "David": 54};
            if (friendsAges.contains("Anna")) {
                $("#content").append("Anna found!");
            } 
            else {
                $("#content").append("Anna not found!");
            }
            

The remove method can be used to remove a particular key and its associated value from a dictionary:

            Dictionary<int> friendsAges = {"Anna": 47, "Betty": 28, "Chris": 35, "David": 54};
            friendsAges.remove("Anna"); 
            for (string name in friendsAges) {
                $("#content").append(name, " ");
            }
            

For a full list of methods in the Dictionary<T> class, see here:

Methods in the Dictionary<T> class

Nullable and Existent Types

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

In the previous chapter, we explored arrays and dictionaries. Arrays can access elements by index, and dictionaries can access elements by string key. However, what if we access an array index that is higher than our total array elements count? What if we attempt to access a non-existent dictionary key?

        import System;

        int[] arr = [ 1, 2, 3 ];
        arr[1000]; // ?

        Dictionary<int> dict = { "a": 1 };
        dict["b"]; // ?
        

The idea of accessing non-existent elements of containers, such as arrays and dictionaries, led to the invention of "existent types." Existent types are exclusive to JS++ and are co-invented by me and Anton Rapetov.

In languages preceding JS++, such as C++, Java, and C#, accessing a non-existent element would result in program termination from segmentation faults or uncaught exceptions. In JS++, your program can't crash or exit prematurely from an "out-of-bounds" access, and this is checked by the compiler. The checking incurs almost no compile time overhead; in fact, we've shown that existent types can result in only a ± 1ms (millisecond) difference in compile times for complex projects.

Existent Types

An existent type describes whether a container access is within-bounds or out-of-bounds. Here's a basic example:

            int[] arr = [ 1, 2, 3 ];
            int+ x = arr[0];    // within-bounds
            int+ y = arr[1000]; // out-of-bounds
            

Existent types use the + type annotation syntax. Existent types are also known as the "bounds-checked type;" to aid your understanding of existent types, here's how code for existent types might be generated:

            int[] arr = [ 1, 2, 3 ];
            int+ x = 0 < arr.length ? arr[0] : undefined;       // within-bounds
            int+ y = 1000 < arr.length ? arr[1000] : undefined; // out-of-bounds
            

In other words, existent types don't just stop at the type checker. When existent types are encountered, code will be generated to perform bounds checking. Bounds checking means that - at runtime - the container access will be checked to ensure that it is "within-bounds" and not attempting to access a non-existent element. If an out-of-bounds access occurs, the variable with the existent type will be assigned a value of undefined.

In our example above, x is within-bounds and will have the value of the first element of arr (1). Meanwhile, y is out-of-bounds because the index 1000 is larger than the array's size of three elements. Thus, y has a value of undefined.

'null' vs. 'undefined'

An existent type cannot be the element type for a container such as an array. It's a compile-time error if you try:

            int+[] arr = [ 1, 2, undefined, 3 ];
            

[ ERROR ] JSPPE5204: Existent type `int+' cannot be used as the element type for arrays at line 1 char 0

In order to understand this concept, we have to understand some JavaScript. In principle, JavaScript differentiates between two values: null and undefined. null means the value exists but is an "empty value" while undefined means no value exists at all. This is most easily understood via variable declarations:

            var a = null;
            var b;

            console.log(a); // null
            console.log(b); // undefined
            

In the above JavaScript code, the variable 'a' was declared and initialized to null (a value exists but represents an "empty" value). Meanwhile, the variable 'b' was declared but not initialized. Thus, b has the value 'undefined' (no value exists at all).

This sounds fine at first. However, JavaScript doesn't actually apply this rule in practice:

            var a = null;
            var b;
            var c = undefined;

            console.log(a); // null
            console.log(b); // undefined
            console.log(c); // undefined
            

JS++ has different semantics. We want you to be able to express "empty" values. For example, a file that was just created might have a creation date, but it won't necessarily have a "last access" date. JS++ allows you to express "empty" values with nullable types. In JS++, null means "empty" value, but undefined only means "out-of-bounds access." This distinction is important to understand if you want to understand why JS++ does not allow existent types to be the element type. In JavaScript, you can have an array of undefined values:

            var arr = [ undefined, undefined, undefined ];
            

Thus, JavaScript is unable to distinguish a within-bounds 'undefined' value from an out-of-bounds 'undefined' value. JS++ does not have this problem. However, if you want to express emptiness...

Nullable Types

Nullable types allow you to declare that data can also have the value null:

            int? x = 1;
            x = null; // OK
            

Note that a nullable type cannot be assigned the value 'undefined'. Besides this, nullable types don't suffer the restrictions of existent types and should be used when emptiness needs to be expressed. For example, the following array can contain int values and empty (null) values:

            int?[] arr = [ 1, null, 2, null, 3 ];
            

However, the above array now poses a new problem: what happens if we access an out-of-bounds element?

The Combined Nullable + Existent Type

When we have an array of nullable-type elements, out-of-bounds accesses are still represented with existent types. JS++ allows us to combine nullable and existent types using the ?+ syntax:

            int?[] arr = [ 1, null, 2, null, 3 ];

            int?+ x = arr[0];   // 1, within-bounds
            int?+ y = arr[1];   // null, within-bounds
            int?+ z = arr[100]; // undefined, out-of-bounds
            

The following illustrates the possible type combinations for nullable and existent types:

            int a = 1;   // 'int' only
            int? b = 1;  // 'int' or 'null'
            int+ c = 1;  // 'int' or 'undefined'
            int?+ d = 1; // 'int' or 'null' or 'undefined'
            

So far, we've only discussed arrays. However, nullable and existent types can also be used for dictionaries and other containers. Here's a creative example using System.Dictionary<T>:

            import System;
 
            Dictionary<bool?> inviteeDecisions = {
                "Roger": true,
                "Anton": true,
                "James": null, // James is undecided
                "Qin": false
            };
             
            bool?+ isJamesAttending = inviteeDecisions["James"]; // 'null'
            bool?+ isBryceAttending = inviteeDecisions["Bryce"]; // 'undefined'
            

In the above code, we use the ?+ syntax to combine nullable and existent types. We're throwing a party, and we want to keep track of the decisions of our invitees. If the invitee's decision is 'true', he's coming to the party. If the invitee's decision is 'false', he won't be attending. If the invitee's decision is 'null', he is undecided. Finally, if the invitee's decision evaluates to 'undefined', he was not actually invited.

Safe Default Operator

By default, there is no automatic conversion from an existent type T+ to T. Concretely, you cannot assign a value of type int+ to int without getting an error:

            int[] arr = [ 1, 2, 3 ];
            int+ x = arr[0];    // within-bounds
            int+ y = arr[1000]; // out-of-bounds

            int a = x;
            

[ ERROR ] JSPPE5206: Cannot convert existent type (`int+') to `int'. To manually convert and avoid exceptions, try using the safe default operator '??'. You can also perform an explicit cast to `int', but it can cause a runtime 'System.Exceptions.CastException' at line 5 char 8

We will explore later in this chapter how to cast correctly (to avoid runtime exceptions... despite what the error message says), but, first, let's explore the better option: the safe default operator ??:

a ?? b

The safe default operator ?? will start by evaluating the expression on its left-hand side (a). If the expression on the left-hand side evaluates to undefined (or null for nullable types), then the evaluated value on the right-hand side of the operator (b) is returned. If the left-hand side does not evaluate to undefined (or null for nullable types), then the evaluated value of the left-hand side (a) is returned.

In simpler terms, the safe default operator (??) allows you to provide an alternative value if an out-of-bounds access occurred (or if a null value is encountered for nullable types). Let's change our code above to use the safe default operator:

            import System;

            int[] arr = [ 1, 2, 3 ];
            int+ x = arr[0];    // within-bounds
            int+ y = arr[1000]; // out-of-bounds

            int a = x ?? 0;
            int b = y ?? 0;

            Console.log(a);
            Console.log(b);
            

On Windows, right-click the file and select "Execute with JS++". In Mac or Linux, run the following command in your terminal:

> js++ --execute test.jspp

You should see the following output:

1
0

Observe that our within-bounds access (x) was successfully converted from int+ to int and retained its value: the first element of arr (1). Meanwhile, our out-of-bounds access (y) was also converted, but we used the "alternative value" (the right-hand side) of the ?? safe default operator. Thus, y was also converted to int but with a value of zero.

In most cases, when using the safe default operator, the right-hand side will usually be supplied with the default value for the type you want to convert to. For example, zero (0) for int, an empty string ("") for string, and false for bool. JS++ does not provide default values for you because conversions involving existent types should be handled on a case-by-case basis; for example, accidentally default initializing a timeout or price value to zero will incur different bug severities compared to default initializing a word count to zero for a missing word. Requiring a default value via the safe default operator is by design. It would have been a simple change for the design team to add an automatic conversion from T+ to T to make existent types less verbose, but we didn't want to open up your code to bugs.

The following table describes what the safe default operator checks for each type:

Type Checks for...
Nullable (?) null
Existent (+) undefined
Nullable + Existent (?+) null and undefined

Safe Navigation Operator

Once again, in order to understand JS++, we have to understand JavaScript. Besides being unable to distinguish a within-bounds undefined from an out-of-bounds undefined, JavaScript also suffers from another problem when it comes to arrays and other containers:

            var arr = [ 1 ];
            console.log( arr[1000].toString() ); // this will crash
            console.log( "This will never get logged." );
            

In the above code, we try to access the 1000th element of 'arr' via arr[1000]. However, the 'arr' array only has one element. Since JavaScript doesn't perform compilation, it doesn't perform compile-time error checking like JS++. Thus, the method call of 'toString' on the 1000th element, arr[1000], escapes notice. Finally, when the script gets executed, it crashes with a TypeError. Line 3 will not get executed.

Now, let's try and convert the above code to JS++. Start by changing the type of the array from 'var' to 'int[]', and we use 'Console.log' (via the 'System' module) rather than 'console.log':

            import System;
 
            int[] arr = [ 1 ];
            Console.log( arr[1000].toString() );
            Console.log( "This will eventually get logged." );
            

Notice that I also changed the string from "This will never get logged" to "This will eventually get logged." You'll also notice we still attempt the same out-of-bounds access on the array by trying to access the 1000th element even though the array contains only one element. Try to compile. You'll get this error:

[ ERROR ] JSPPE5200: The '.' operator cannot be used for nullable and existent types (`int+'). Please use the '?.' safe navigation operator instead at line 4 char 13

The error message is very descriptive and tells us exactly the location where the error occurred and suggests a fix. Let's try that fix:

            import System;
 
            int[] arr = [ 1 ];
            Console.log( arr[1000]?.toString() );
            Console.log( "This will eventually get logged." );
            

You'll notice that we are now using the safe navigation operator '?.'. The safe navigation operator will check if the left-hand side is undefined (or null for nullable types); if it is, the safe navigation operator will evaluate to undefined (or null for nullable types). Otherwise, if the object exists, the safe navigation operator will try to access the member of the object. In this case, we are trying to access the 'toString' member if 'arr[1000]' exists. Since 'arr[1000]' does not exist, 'undefined' will be returned. Thus, since either the object member is accessed or 'undefined' is returned, we can understand that - for existent types - the safe navigation operator '?.' will return a type of T+ (an existent type).

Here's a table describing the return types for the safe navigation operator:

Type Returns...
Nullable (?) T?
Existent (+) T+
Nullable + Existent (?+) T?+

However, since '?.' will return an existent type, we have a problem if we try to compile with only the '.' changed to '?.':

[ ERROR ] JSPPE5024: No overload for `System.Console.log' matching signature `System.Console.log(string+)' at line 4 char 0

'System.Console.log' will accept an argument of type 'string' but not 'string+'. This is a common error you'll have to deal with when using existent types so I wanted to make sure it was covered in the tutorial. While there are multiple ways to deal with converting 'string+' to 'string' - as you'll discover when you finish reading this full chapter - we'll use the operator that we've already covered: the safe default operator '??'.

            import System;
 
            int[] arr = [ 1 ];
            Console.log( arr[1000]?.toString() ?? "out of bounds" );
            Console.log( "This will eventually get logged." );
            

The output should look like this:

out of bounds
This will eventually get logged.

Unlike JavaScript, as long as you are using internal types, JS++ cannot crash or throw exceptions from an access on an undefined value. When existent types are used correctly, you should never get premature or unexpected program termination.

Let's also try a within-bounds access using the safe navigation operator:

            import System;
 
            int[] arr = [ 1 ];
            Console.log( arr[0]?.toString() ?? "out of bounds" );
            Console.log( arr[1000]?.toString() ?? "out of bounds" );
            Console.log( "This will eventually get logged." );
            

The final output should look like this:

1
out of bounds
This will eventually get logged.

Inspecting 'undefined'

It's not uncommon to write code inside a loop or function that assumes only within-bounds accesses occur. Oftentimes, rather than desiring an exception that can terminate the program, we'd rather just "skip" complex logic when we detect an out-of-bounds error. We can do that in JS++ with an 'if' statement that checks for 'undefined':

            import System;
 
            int[] arr = [ 1 ];
             
            for (int i = 0; i < 10; ++i) {
                int+ element = arr[i];
                if (element == undefined) {
                    continue;
                }
             
                int x = element ?? 0; // the ?? 0 path never gets followed
             
                Console.log(x + 1);
                Console.log(x + 2);
                Console.log(x + 3);
            }
            

In the code above, we simply skip the iteration if an out-of-bounds access was detected. The rest of the code, after the 'if' statement, operates with the assumption that we are only dealing with within-bounds values. The output will be:

2
3
4

Notice I marked a line with a comment:

int x = element ?? 0; // the ?? 0 path never gets followed

The reason the ?? 0 path never gets followed is because we've already checked that the 'element' variable does not equal 'undefined'. Alternatively, we can cast...

Casting Unsafely

In JS++, some type conversions cannot be proven to be safe by the compiler and need to be performed explicitly. Consider the following example:

            import System;

            int x = 1;
            byte y = x;
            

[ ERROR ] JSPPE5016: Cannot convert `int' to `byte'. A cast is available at line 4 char 9

Since we know the value one (1) is within the range of the 'byte' data type (0-255), we can provide an explicit cast to make the error go away:

            import System;

            int x = 1;
            byte y = (byte) x;
            

The syntax for a type cast is:

(type) expression

Let's re-visit a previous existent types example where we received an error suggesting to use either the safe default operator or a cast. We decided to go with the safe default operator because it was... safe. The safe default operator can never result in runtime program termination. In using existent types, the safe default operator will suffice for the vast majority of cases. However, there are times when you might know the cast is safe or might not want to supply a default value.

Here's our previous example:

            int[] arr = [ 1, 2, 3 ];
            int+ x = arr[0];    // within-bounds
            int+ y = arr[1000]; // out-of-bounds

            int a = x;
            

[ ERROR ] JSPPE5206: Cannot convert existent type (`int+') to `int'. To manually convert and avoid exceptions, try using the safe default operator '??'. You can also perform an explicit cast to `int', but it can cause a runtime 'System.Exceptions.CastException' at line 5 char 8

Let's first experiment by casting the variable 'x' from 'int+' to 'int':

            import System;

            int[] arr = [ 1, 2, 3 ];
            int+ x = arr[0];    // within-bounds
            int+ y = arr[1000]; // out-of-bounds

            int a = (int) x;
            Console.log(a);
            

There should be no problems, and you should see this output:

1

However, let's try casting the variable 'y' (which made an out-of-bounds access) from 'int+' to 'int':

            import System;

            int[] arr = [ 1, 2, 3 ];
            int+ x = arr[0];    // within-bounds
            int+ y = arr[1000]; // out-of-bounds

            int a = (int) y;
            Console.log(a);
            

Execution Error: System.Exceptions.CastException: Failed to cast `undefined' to `int'

An incorrect cast led to a runtime error. Let's re-visit the original error message before we started casting (with relevant details in bold):

JSPPE5206: Cannot convert existent type (`int+') to `int'. To manually convert and avoid exceptions, try using the safe default operator '??'. You can also perform an explicit cast to `int', but it can cause a runtime 'System.Exceptions.CastException'

Now you can see why we started with and recommended the safe default operator: it cannot cause runtime errors. Now you can also see why the error message warns you against the explicit cast. However, there is a way to use casts safely.

Casting Safely

Now that we've learned what unsafe casting looks like, we can learn how to cast safely and correctly when using existent types. The rule is very simple: check that you don't have an out-of-bounds access before you perform a cast. Here's an example:

            int[] arr = [ 1, 2, 3 ];
            int+ x = arr[0];    // within-bounds
            int+ y = arr[1000]; // out-of-bounds

            if (x != undefined) {
                int a = (int) x;
            }
            if (y != undefined) {
                int b = (int) y;
            }
            

Now you should never get runtime errors if you want to "cast away" the existent type.

Once again, we want to stress: When existent types are used correctly, you should never get premature or unexpected program termination.

Before we announced existent types, we tested the feasability and usability of existent types on 11,000 lines of code. Our findings were that you should almost never need to cast, and the safe default operator '??' will handle most cases. In our refactoring of the 11,000 lines of code, we only had one or two instances where casts were needed, and, in those instances, the casts were performed safely by checking for 'undefined' first.

Here's the relevant original code (before existent types were introduced):

            FeedItem item = this.queue.pop();

            Crawler _this = this;
            auto tokenizer = new TextTokenizer();
            auto docProcessor = new DocumentProcessor();
            string url = item.url;
            Date pagePublishedDate = item.date;
            

And here's the refactoring:

            FeedItem+ item = this.queue.pop();
            if (item == undefined) {
                return;
            }
            FeedItem feedItem = (FeedItem) item;

            Crawler _this = this;
            auto tokenizer = new TextTokenizer();
            auto docProcessor = new DocumentProcessor();
            string url = feedItem.url;
            Date pagePublishedDate = feedItem.date;
            

It would also be equivalent to refactor like so (without the need for casts):

            FeedItem+ item = this.queue.pop();
            if (item == undefined) {
                return;
            }

            Crawler _this = this;
            auto tokenizer = new TextTokenizer();
            auto docProcessor = new DocumentProcessor();
            string url = item?.url ?? "";
            Date+ pagePublishedDate = item?.date;
            if (pagePublishedDate == undefined) {
                return;
            }
            

Notice in our code that we are applying the same concepts we've been teaching in this chapter: checking for 'undefined', "skipping" code (e.g. with the 'return' or 'continue' statements), casting safely, etc.

If the code from our test project is confusing, it's because we haven't taught classes and user-defined types yet. We'll get to that starting in the next chapter. For readers coming to JS++ from languages that have classes, the above code should illustrate further how to use existent types. Casts are the one corner case with existent types that can cause runtime exceptions, but, if used correctly, it should never happen.

Nevertheless, in the vast majority of cases, the safe default operator '??' should suffice and should be favored over casts.

Intuition and User Experience (UX)

In C++, there is operator[] and .at(). The former does not perform bounds checking; the latter differs from the former because it performs bounds checking and throws an std::out_of_range exception. Needless to say, the reason this design exists in C++ is because C++ programmers intuitively have a sense of whether they might perform an out-of-bounds access and don't want to pay the performance penalty for bounds checking.

... And it's not just C++ programmers. Most programmers have a sense of intuition beyond the compiler's knowledge. Intuition was one of the fundamentals behind JS++ "type guarantees," and JS++ introduced a sound, gradual type system that is fault-tolerant and scales for complex projects. Likewise, for containers, we have a sense of intuition:

            import System;

            int[] arr = [ 1, 2, 3 ];
            for (int i = 0, len = arr.length; i < len; ++i) {
                arr[i]++;
            }
            

A programmer only needs to look at the above code to know that an out-of-bounds error will never occur.

Why is intuition important? Because, for existent types, it is solves major usability issues that would have prevented existent types from becoming practical. The above increment code is actually valid JS++ code with existent types. For common operations (such as ++ and +=), code will be generated so that an error value (undefined) will be returned if the operation occurred on an out-of-bounds element. If the operation occurred for a within-bounds element, it will succeed.

Back to intuition. If you intuitively believe you might make an out-of-bounds access, you can customize how you want to handle the error by first checking for the error value occurring:

            import System;

            int[] arr = [ 1, 2, 3 ];
            for (int i = 0, len = arr.length; i < len; ++i) {
                int+ x = arr[i]++;
                if (x != undefined) {
                    Console.log("Success!");
                }
                else {
                    Console.error("Increment on out-of-bounds element.");
                    continue;
                }

                // ...
            }
            

I explicitly added the continue statement even though it seems unnecessary. Oftentimes, we don't actually want our program to potentially terminate with an IndexOutOfBoundsException or the like. When we're iterating an array, usually we can just "skip" to the next iteration (e.g. via continue) if an error condition occurred. This is much more eloquently described with if/else than try/catch.

Effectively, you get a NOP ("no operation") instead of an exception for ++, +=, and assignment (=) if the operation is performed on an out-of-bounds element. Semantically, a NOP operation remains correct, and it's also better than an exception that can terminate the program. We could have designed this more "safely," but we chose user experience (UX). If you intuitively fear there might be an error condition, check for undefined at runtime.

Classes, OOP, and User-defined Types

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

Up until now, we've been declaring variables, looping over data, and writing 'if' and other conditional statements. These operations comprise the "imperative programming" paradigm where we describe "how" a program operates step by step (or, more specifically, statement by statement).

Oftentimes, in real-world programming, we want to be able to describe real-world objects. For example, in an employee database, we need to be able to describe "employees" – and maybe even specific types of employees such as programmers, managers, salespeople, and so on. In a video game, we need to be able to describe the hero, the enemies, bullets, weapons, equipment, and other items. This need gave rise to the object-oriented programming (OOP) paradigm, most notably with the C++ programming language (although OOP itself predates C++) and then extending to Java, Python, C#, PHP, Objective-C, Swift, and many other modern languages.

JS++ provides access to object-oriented programming (OOP) via classes, which also create user-defined types. JS++ is an extension of the JavaScript ECMAScript 3 specification, which did not provide class support. Furthermore, JS++ classes are unique from class systems and libraries that tried to add OOP to JavaScript, a language that is "dynamically-typed" – where data types are determined at runtime (as we explored previously). Instead, JS++ classes operate naturally with many compile-time concepts where static typing and static analysis are used (where data types and errors are analyzed and checked at compile time): nominal typing, method overloading, parametric polymorphism (generic programming), compile-time overload resolution, virtual methods, and so on. In this way, object-oriented programming in JS++ is very similar to the OOP available in C++, Java, and C#. Therefore, design patterns and best practices that were developed over decades of experience in the aforementioned programming languages, from banking to rocketry, are also immediately applicable to JS++.

In this chapter, we will introduce basic OOP in JS++ by creating animal objects that we will render to a web page. We will then progressively add interactivity to these animal objects to illustrate core OOP concepts. We will also cover the four fundamentals of OOP: abstraction, encapsulation, inheritance, and polymorphism.

Classes and User-Defined Types

Classes are the basic foundation of object-oriented programming in JS++. We can declare a class using the 'class' keyword:

            class Animal
            {
            }
            

By declaring a class, you are also creating your own user-defined data type. To use a game development analogy, if you want to declare a function that operates on bullets, you don't want data representing potion objects to potentially be operated on. This goes back to the correctness guarantees that JS++ provides as we previously explored.

Since classes allow us to create our own user-defined data types, let's explore how this can be used in practice. Create a folder named 'OOP'. Inside the 'OOP' folder, create a file named error.jspp and enter the following code:

            class Animal
            {
            }
            class Chair
            {
            }

            void startWalking(Animal a) {
            }

            Animal dog = new Animal();
            Chair chair = new Chair();
            startWalking(chair); // intentional, let's see the error
            

Try compiling. You should see this compile error:

[ ERROR ] JSPPE5024: No overload for `startWalking' matching signature `startWalking(Chair)' at line 13 char 0 at error.jspp

We want our 'startWalking' function to make an object of type 'Animal' start walking. We don't want to accidentally or potentially be able to pass in an object of type 'Chair'. Change the 'startWalking' function call:

            // startWalking(chair); // intentional, let's see the error
            // to:
            startWalking(dog);
            

Although our 'startWalking' function is an empty function that doesn't do anything (e.g. make an actual 'Animal' object walk), we're able to see the basics of how user-defined types can be used in real-world code to prevent mistakes. If you compile the revised error.jspp to pass in the 'dog' object, it should successfully compile with no errors.

You can now delete error.jspp. We won't be needing it anymore. It's always good to keep your code clean and remove code that is no longer used.

Instantiation

You may have noticed that we used the 'new' keyword a couple times in our previous code:

            Animal dog = new Animal();
            Chair chair = new Chair();
            

The 'new' keyword is used for a process called "instantiation." Classes are like "blueprints" for objects. The objects are the "instances" of the class. In the two lines of code above, 'dog' is the object instance of the 'Animal' blueprint (class) and 'chair' is an instance of the 'Chair' blueprint. Since we can have multiple "instances" of the class, this enables us to create multiple dogs with different attributes, such as dogs with different names, different weights, descending from different breeds, and so on.

To recap: the 'class' keyword creates the blueprint, and the 'new' keyword creates an object/instance of that blueprint.

Setting Up Our OOP Project

We're now going to begin our OOP project. We'll create classes for different animals, render them to a web page, make them talk with speech bubbles, and more.

First, we need to download some resources. Inside the 'OOP' project folder, create four subfolders: 'build', 'libs', 'src', and 'style'.

Head over to Icofont.com to download Icofont. Icofont is an "icon font." For those of you familiar with the Windows "Wingdings" font, this is the same idea. Icon fonts give us graphics and icons – in the form of font characters – that we can use in our applications. Icon fonts have the added advantage that we can change the color of the icon simply by changing the font color. This makes icon fonts ideal for the web and user interfaces.

Download and unzip Icofont to your 'libs' subfolder. Your directory structure should now look like this:

            OOP
            |_ build
            |_ libs
                 |_ Icofont
                      |_ css
                      |_ fonts
            |_ src
            |_ style
            

In the 'style' subfolder, create an empty 'style.css' file.

In your 'src' subfolder, create an empty main.jspp file. Now, again in the 'src' subfolder, create a folder named 'Animals' and put the following *empty* files inside:

  • Animal.jspp
  • Cat.jspp
  • Dog.jspp
  • Panda.jspp
  • Rhino.jspp

Finally, in our root 'OOP' project folder, create an 'index.html' file with the following code:

            <!DOCTYPE html>
            <head>
            <title>JS++ Animals OOP Project</title>
            <link rel="stylesheet" type="text/css" href="lib/icofont/css/icofont.css">
            <link rel="stylesheet" type="text/css" href="style/style.css">
            </head>
            <body>

            <div id="content"></div>

            <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
            <script src="build/app.jspp.js"></script>
            </body>
            </html>
            

The HTML should be straightforward by now. We created a 'div' element which will be the container for the content we will dynamically generate via jQuery and JS++. The new tags are for including our CSS files used for styling. Also worth noting is the 'script' tag pointing to "build/app.jspp.js" which will contain our generated JS++ application. (When JS++ compiles multiple input source files, the default output name is usually 'app.jspp.js'.)

Your final directory structure should look something like this:

            OOP
            |_ build
            |_ libs
                 |_ Icofont
                      |_ css
                           |_ icofont.css
                      |_ fonts
                           |_ icofont.eot
                           |_ icofont.svg
                           |_ icofont.ttf
                           |_ icofont.woff
            |_ src
                 |_ Animals
                      |_ Animal.jspp
                      |_ Cat.jspp
                      |_ Dog.jspp
                      |_ Panda.jspp
                      |_ Rhino.jspp
                 |_ main.jspp
            |_ style
                 |_ style.css
            index.html
            

Classes & OOP: Fields and Methods

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

Creating and Rendering an Animal

Open 'src/Animals/Cat.jspp' and enter the following code:

            external $;

            module Animals
            {
                class Cat
                {
                    void render() {
                        var $element = $(
                            """
                            <div class="animal">
                                <i class="icofont icofont-animal-cat"></i>
                            </div>
                            """
                        );

                        $("#content").append($element);
                    }
                }
            }
            

One thing you may immediately notice is the multiline string ("""..."""). When we surround our string in triple quotation marks, we can write a "multi-line" string. Multi-line strings are a feature of JS++ that are especially useful when dealing with HTML. You'll notice that, with multi-line strings, we didn't have to escape our double quote characters (") or newline characters.

Besides the multi-line string, we're just passing some HTML to jQuery via the $(...) as usual. jQuery will recognize this as HTML and dynamically create the HTML elements for us. However, the dynamically-created HTML elements are still only held in memory unless we render it to the page. We do that with this line:

$("#content").append($element);

You'll notice we named our variable for the jQuery element as $element. It is a common naming convention to prefix variables holding jQuery objects with the $ sign.

You may also have noticed that we declare the data type for the jQuery $element variable as 'var'. As we discussed in previous chapters, there may not always be a corresponding JS++ data type for complex objects so we can just use 'var' in these cases (or even just for convenience).

Side Note: jQuery and the Document Object Model (DOM) API for manipulating web pages can be classified as "highly-dynamic." Some large companies were incorrect to try to add static data types in these cases as there are many corner cases where static data types will be incorrect or fail – such as for ECMAScript "host objects, " which includes the DOM API, where "implementation-defined" behavior, such as different browser implementations of the same DOM API methods, is valid according to the language specification (and indeed occurs in real-world implementations). Another example is the garbage collector implementation in versions of Internet Explorer where the GC can reclaim non-cyclic, in-use host objects (such as the "htmlfile" ActiveXObject used for real-time streaming) too early, a scenario that is not amenable to static analysis. Despite their convenience, the static data types in these cases create a "false sense of security." However, discussion of these topics is outside the scope of this tutorial.

You will notice that we declared a function inside our 'Cat' class. A function declared inside a class is commonly called a "class method" or just "method" for short. Functions that are not members of a class are known as "free functions."

We declared a class inside a module, so this file by itself will not compile. We need to create a "main file" to act as the program entry point. In your 'src' folder (the parent folder of the 'Animals' folder), you'll recall we created an empty main.jspp file. Open the main.jspp file and enter these lines of code:

            import Animals;

            Cat cat = new Cat();
            cat.render();
            

We first instantiate the class to get a class instance. Once we have a class instance, we call the 'render' method on that specific class instance.

Compiling

Compilation is going to be slightly different compared to our previous tutorial examples due to our deep directory structure. Mac/Linux users won't have to make much of an adjustment, but, for Windows users, we have to start using the Command Prompt.

For Mac/Linux users, just open your terminal to the 'OOP' code folder and enter the following command:

$ js++ src/ -o build/app.jspp.js

For Windows users, open the Command Prompt. Navigate to the directory of the OOP 'code' folder (using the 'cd' command). Once we navigate to the folder, we enter the same command as the Mac/Linux users:

> js++ src/ -o build/app.jspp.js

If everything worked, you should see a green "OK" as shown in the screenshot above (for all operating systems: Windows, Mac, and Linux).

Open index.html (in the root 'OOP' folder) in your web browser. You should see a small cat icon rendered to the page:

Styling the Animals

Right now, our cat is quite small and hard to see. Let's modify the styling to make our cat bigger and clearer.

Open style.css in the 'style' folder. It should be empty, but we'll add one simple CSS rule to make our cat clearer:

.animal i { font-size: 50px; }

Save style.css and refresh index.html. You should see a larger cat.

Class Fields

Beyond methods that define the behavior for a class, classes can also hold data of their own. At its core, you can think of classes as data plus methods that operate on that data. For example, with pets like cats, we may want to be able to give the cat a name. The name is the data and examples of methods might be functions that allow us to set or change the name.

Class fields allow us to specify data that is exclusive to the class. Fields are just variable declarations:

            class Cat
            {
                string name;
            }
            

Class fields differ from regular variable declarations because they can only be accessed via the class or class instances. Furthermore, we declared a 'name' field that is exclusive to a class instance above; this means that each unique instance of the class will have its own unique name data.

Data that is unique to a specific instance can be very useful, especially when dealing with a large number of similar objects. However, our current code that renders the cat to the page actually doesn't keep data unique to an instance! Let's observe; change the main.jspp code as follows to call render() a second time:

            import Animals;

            Cat cat = new Cat();
            cat.render();
            cat.render();
            

Compile the code and open index.html. You should see two cats rendered, but we have only one instance of the 'Cat' class. This is not ideal; rather, we should like to require two 'Cat' instances if we want to render two cats to the page. In order to do that, we have to examine our render() code:

            class Cat
            {
                void render() {
                    var $element = $(
                        """
                        <div class="animal">
                            <i class="icofont icofont-animal-cat"></i>
                        </div>
                        """
                    );

                    $("#content").append($element);
                }
            }
            

Do you see what's wrong?

Each time the render() method is called, we are calling jQuery to create a new object, and then we render that new object to the page via jQuery's append() method. What we need to do is to make the creation of the page elements exclusive to class instances. We can do this by simply moving the variable declaration in render() to a class field. Here's our full code:

            external $;

            module Animals
            {
                class Cat
                {
                    var $element = $(
                        """
                        <div class="animal">
                            <i class="icofont icofont-animal-cat"></i>
                        </div>
                        """
                    );

                    void render() {
                        $("#content").append($element);
                    }
                }
            }
            

We've done nothing in the above code other than move the variable declaration from render() to the class itself so it becomes a field. Now, the field will only be initialized when we instantiate the class. In other words, the jQuery function call you see that turns HTML into a jQuery object will not be executed until we instantiate our class using the 'new' keyword.

Keep your code exactly as you had it with the two render() calls for the same class instance. However, with the updated Cat.jspp, compile your code again. Open index.html. You should see only one cat rendered to the page.

Now let's try creating two cats by updating main.jspp to use two class instances:

            import Animals;

            Cat cat1 = new Cat();
            cat1.render();
            Cat cat2 = new Cat();
            cat2.render();
            

You should now see two cats, one for each class instance:

Naming our Animals with Fields and Methods

While our first example for class fields involved naming, we never actually added a name field to our classes. However, rather than just naming our cats, let's also make it tangible by making the name visible in the web browser when we hover over the animal. As we showed in our previous example, fields like the name should be unique to the class instance – no two cat elements on the page should be showing the same name if they were given different names.

Insert the following code into Cat.jspp:

            external $;

            module Animals
            {
                class Cat
                {
                    string name;

                    var $element = $(
                        """
                        <div class="animal">
                            <i class="icofont icofont-animal-cat"></i>
                        </div>
                        """
                    );

                    void setName(string name) {
                        this.name = name;
                    }

                    void render() {
                        $("#content").append($element);
                        $element.attr("title", name);
                    }
                }
            }
            

We added a new field: 'name' with type 'string'. We also added a new method 'setName'. It contains only one line of code:

this.name = name;

You'll notice the method takes one parameter called 'name':

            void setName(string name) {
                this.name = name;
            }
            

In order to disambiguate the 'name' parameter from our 'name' class field, we need to use 'this'. When two conflicting names appear in the same method, this is known as "variable shadowing." It's a convenience so that we don't have to come up with different variable names to describe the same concept. Thus, what our statement is saying is: set the 'name' class field ('this.name') to the 'name' value passed in as an argument to our method.

The 'this' keyword inside a class refers to the class instance. Class instance methods, like the 'setName' method we just defined, cannot be called unless the class has been instantiated first. Once we've instantiated the 'Cat' class, we can call the 'setName' method. When we call the 'setName' instance method, the 'this' keyword refers to the class instance that executed the method. Thus, the above statement will set the 'name' field of the class instance that 'setName' is being executed on; it is always unique to the class instance; thus, no two class instances will end up having the same 'name' field set after a 'setName' method call.

Finally, we added the following statement to our 'render' method:

$element.attr("title", name);

This will set the HTML 'title' attribute of our cat HTML element that we render to the page. By setting the 'title' attribute, we can set the text that appears when we hover over an HTML element. In this case, when we hover over our cat element, we will see its name.

Before we can see our results, we must set the names of our cats in main.jspp. Let's do that:

            import Animals;

            Cat cat1 = new Cat();
            cat1.setName("Kitty");
            cat1.render();
            Cat cat2 = new Cat();
            cat2.setName("Kat");
            cat2.render();
            

Make sure 'setName' is called before the 'render' method.

Compile the code. Once again, for Windows, Mac, and Linux users, the command is now all the same:

> js++ src/ -o build/app.jspp.js

If the program compiled successfully, open index.html. Hover your name over each cat. You should see its name.

Classes & OOP: Getters and Setters

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

In our previous example, we defined a 'setName' method that sets a class 'name' field we declared. A method whose sole responsibility is to write to or modify a class field is known as a "setter" or "setter method." Conversely, a method whose sole responsibility is to return the current data of a class field is known as a "getter" or "getter method."

Containers like arrays have methods like 'length' which are getter methods:

        int[] arr = [ 1, 2, 3 ];
        arr.length; // 3
        

The 'length' method for arrays returns the size of the array, determined by the number of array elements. However, you may have noticed a peculiarity: we didn't have to use parentheses to call the 'length' method. This is because the 'length' property of arrays is defined in a special way. It turns out we can define our own classes to have such special methods.

Let's start by re-defining our 'setName' method as a setter method. Open Cat.jspp and simply add the 'property' keyword in front of 'setName' like so:

        external $;

        module Animals
        {
            class Cat
            {
                string name;

                var $element = $(
                    """
                    <div class="animal">
                        <i class="icofont icofont-animal-cat"></i>
                    </div>
                    """
                );

                property void setName(string name) {
                    this.name = name;
                }

                void render() {
                    $("#content").append($element);
                    $element.attr("title", name);
                }
            }
        }
        

At this point, if you try to compile, you'll get an error (JSPPE0150). We need to edit our main.jspp file to reflect our change to a setter. Since we defined 'setName' as a setter, we can no longer call it using parentheses but we must use the assignment (=) operator instead:

        import Animals;

        Cat cat1 = new Cat();
        // cat1.setName("Kitty");
        cat1.setName = "Kitty";
        cat1.render();
        Cat cat2 = new Cat();
        // cat2.setName("Kat");
        cat2.setName = "Kat";
        cat2.render();
        

Now, if you try to compile the project, it should be a success.

That was quite easy! The only detail we may want to consider at this point is that the name is a property of the cat. 'setName' implies an action. Since we cannot have fields and methods with conflicting names, we can rename our private 'name' field to any of the numerous naming conventions: mName, _name, etc. In this tutorial, we're going to prefer the underscore to avoid name clashes since, in some dynamic languages (including JavaScript and Python), underscores are used to "denote" privacy (even if they aren't really "private" in practice). By renaming our private 'name' field, this frees us up to use the identifier 'name' as a setter method. Change the Cat.jspp code as follows:

        external $;

        module Animals
        {
            class Cat
            {
                string _name;

                var $element = $(
                    """
                    <div class="animal">
                        <i class="icofont icofont-animal-cat"></i>
                    </div>
                    """
                );

                property void name(string name) {
                    _name = name;
                }

                void render() {
                    $element.attr("title", _name);
                    $("#content").append($element);
                }
            }
        }
        

Also, change main.jspp to reflect this change:

        import Animals;

        Cat cat1 = new Cat();
        cat1.name = "Kitty";
        cat1.render();
        Cat cat2 = new Cat();
        cat2.name = "Kat";
        cat2.render();
        

Setter methods allow us to assign a value (write operation). However, if we wanted to get the value (read operation), it won't be allowed unless we define an accompanying getter method. Try to "read" the 'name' field like so:

        import Animals;

        Cat cat1 = new Cat();
        cat1.name = "Kitty";
        cat1.render();
        Cat cat2 = new Cat();
        cat2.name = "Kat";
        cat2.name;
        cat2.render();
        

If you try to compile, you'll get an error:

[ ERROR ] JSPPE0203: No getter defined for `Animals.Cat.name' at line 8 char 0 at main.jspp

As you may have deduced by now, the parameter for a setter method is the value assigned to the property (the value on the right-hand side). In our main.jspp above, the values were "Kitty" and "Kat" strings. Naturally, setter methods are only allowed to accept one parameter. Since getters are a "read" operation, no values need to be accepted; thus, getter methods intuitively do not require parameters. Using this intuition, we can define an accompanying getter method:

        external $;

        module Animals
        {
            class Cat
            {
                string _name;

                var $element = $(
                    """
                    <div class="animal">
                        <i class="icofont icofont-animal-cat"></i>
                    </div>
                    """
                );

                property string name() {
                    return _name;
                }
                property void name(string name) {
                    _name = name;
                }

                void render() {
                    $element.attr("title", _name);
                    $("#content").append($element);
                }
            }
        }
        

Now, if you try to compile the project, you should be able to successfully compile.

As you've seen, if you define a setter without a getter, you can prevent all "read" operations. In contrast, if you define a getter without a setter, you can prevent all "write" operations. If you define both, you can have both read and write operations. This allows you to customize to your needs.

Classes & OOP: Constructors

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

In our cat example, we've been able to instantiate our cat and provide a name separately. However, it may be desirable to require the cat to be named at instantiation so that we don't accidentally forget to name a cat. Constructors allow us to control instantiation.

By default, JS++ provides a constructor for you. This is known as the "default constructor." It is implicitly defined by JS++ if you do not have any constructors that you've explicitly defined. The default constructor takes no arguments and only returns a new instance of the class. To understand the default constructor, we can explicitly define it:

        external $;

        module Animals
        {
            class Cat
            {
                string _name;

                var $element = $(
                    """
                    <div class="animal">
                        <i class="icofont icofont-animal-cat"></i>
                    </div>
                    """
                );

                Cat() {
                }

                property string name() {
                    return _name;
                }
                property void name(string name) {
                    _name = name;
                }

                void render() {
                    $element.attr("title", _name);
                    $("#content").append($element);
                }
            }
        }
        

If you try to compile the project, there should be no problems. The reason is because we are instantiating the 'Cat' class without arguments in our main.jspp file. If you try to provide a few arguments, you will get a compile error for incorrect code.

As you can see from our explicitly-defined default constructor, the constructor has no parameters. Additionally, it doesn't do anything. (Constructors with no actions will still return a new instance of the class. Explicit 'return' statements inside constructors are unnecessary and not allowed because constructors always return a new instance of the class.)

One particular use for constructors is to initialize fields to custom values. Right now, if you instantiate the 'Cat' class, you will get the '_name' field as an empty string. If we want instances of 'Cat' to always have a name, we must require it during instantiation by specifying a constructor.

First, remove the getter and setter methods. Second, change the explicit constructor we defined to take one parameter: a 'string' for the cat's name. Finally, initialize the field to the argument provided to the constructor. (You should know how to do this by now.)

Your code in Cat.jspp should now look like this:

        external $;

        module Animals
        {
            class Cat
            {
                string _name;

                var $element = $(
                    """
                    <div class="animal">
                        <i class="icofont icofont-animal-cat"></i>
                    </div>
                    """
                );

                Cat(string name) {
                    _name = name;
                }

                void render() {
                    $element.attr("title", _name);
                    $("#content").append($element);
                }
            }
        }
        

Next, we have to change main.jspp:

        import Animals;

        Cat cat1 = new Cat("Kitty");
        cat1.render();
        Cat cat2 = new Cat("Kat");
        cat2.render();
        

Compile the project. Open index.html in your web browser. You should see the two cats again. Hover over their images. You should once again see their names.

It's important to note that the implicitly-defined default constructor (that takes zero arguments) is no longer defined. Once you explicitly define a constructor for a class, the default constructor will not be explicitly defined. Thus, the only way to instantiate our 'Cat' class now is to use the constructor that requires a name. If you try to change the code in main.jspp to instantiate a class with zero arguments, you will get a compile error.

Classes & OOP: Inheritance

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

So far, the only type of animal we've defined is a cat (via the 'Cat' class). Our 'Cat' class also requires us to name our cats. Finally, our 'Cat' class performs rendering to the web page. However, what if we wanted to introduce other animals? How should we implement dogs, pandas, and rhinos?

While the simple answer is that we can just copy, paste, and modify our code from Cat.jspp into Dog.jspp, Panda.jspp, and Rhino.jspp, this is usually not good programming. Instead, we might notice that there is a lot of repetition in the design; all the animals need a name, all the animals need to be rendered to our web page, and all the animals can be categorized together. Therefore, we can define the behaviors we need for animals in general (such as rendering to a web page) and have all our animal classes "inherit" this common behavior. Furthermore, some animals might not need names; for example, domesticated animals like cats and dogs might need names, but we might not want to name our pandas and rhinos.

First, let's start by examining Cat.jspp. What data or behavior in Cat.jspp should be common to all animals?

From what we've defined so far, it should only be the render() method. We'll use that as the basis for understanding inheritance. Earlier, we created an Animal.jspp file. It's currently empty so open it and let's define an 'Animal' class:

        external $;

        module Animals
        {
            class Animal
            {
                var $element = $(
                    """
                    <div class="animal">
                        <i class="icofont icofont-animal-cat"></i>
                    </div>
                    """
                );

                void render() {
                    $("#content").append($element);
                }
            }
        }
        

This works well as a basic template. However, a keen observer will notice we have a problem: the $element field will always render a cat icon. We'll get back to this later, but, first, let's change Cat.jspp to inherit from our new 'Animal' class:

        external $;

        module Animals
        {
            class Cat : Animal
            {
                string _name;

                Cat(string name) {
                    _name = name;
                }
            }
        }
        

We removed the $element field and render() method from Cat.jspp and we added this to the class declaration:

class Cat : Animal

The colon syntax specifies the inheritance relationship. In this case, our 'Cat' class inherits from the 'Animal' class. In other words, our 'Cat' class extends the 'Animal' class; everything that belongs to the 'Animal' class (fields, getters/setters, methods, etc) also belongs to the 'Cat' class.

In inheritance, our 'Cat' class is known as the "subclass" or "derived class" of 'Animal'. 'Animal' may be referred to as the "superclass" or "base class."

If you try to compile your code right now, you'll still see the cats rendered to the page exactly as before, but, if you hover your mouse over any of the cats, you will not see its respective name. The render() method on 'Cat' is now derived from the 'Animal' class. Since our 'Animal' class does not take names (as we want to be able to generalize the class for wild animals like pandas and rhinos), its render() method likewise does not render the HTML 'title' attribute needed to show a name on mouse over. However, we can make this behavior possible. In order to do that, it requires explanation of access modifiers, which we will now cover.

Classes & OOP: Access Modifiers

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

Access modifiers allow us to change the "visibility" and "access privileges" of a class (or module) member. These are best understood by example.

JS++ has three access modifiers: private, protected, and public.

Examples & Illustrations

A private member is the least permissive. If a member is declared as 'private' it can only be accessed from the class or module it was declared. Here's an example:

            class Animal
            {
                private string name;

                string getName() {
                    return name; // OK
                }
            }
            class Dog : Animal
            {
                string getName() {
                    return name; // Error
                }
            }
            Animal animal = new Animal();
            animal.name;      // ERROR
            animal.getName(); // OK
            

A protected member can be accessed from any subclass or submodule. Here's an example:

            class Animal
            {
                protected string name;

                string getName() {
                    return name; // OK
                }
            }
            class Dog : Animal
            {
                string getName() {
                    return name; // OK
                }
            }
            Animal animal = new Animal();
            animal.name;      // ERROR
            animal.getName(); // OK
            

Finally, there is the 'public' access modifier. The 'public' access modifier is the least permissive. A member declared as 'public' has no restrictions on access and can even be accessed from outside the class (provided it is being accessed from a class instance). Here's an example:

            class Animal
            {
                public string name;

                string getName() {
                    return name; // OK
                }
            }
            class Dog : Animal
            {
                string getName() {
                    return name; // OK
                }
            }
            Animal animal = new Animal();
            animal.name;      // OK
            animal.getName(); // OK
            

Encapsulation

Access modifiers enable encapsulation. Encapsulation is one of the pillars of object-oriented programming (as we discussed in chapter 12) and refers to the bundling of data (fields) and the methods that operate on that data (e.g. methods, getters/setters, etc). In simpler terms: hide your data by making fields private and only enable access to them via public/protected methods, getters, or setters.

The JS++ default access rules enable encapsulation. In JS++, fields have a default access modifier of 'private'. All other class members have a default access modifier of 'public'. In other words, JS++ access rules are "member-sensitive, " whereas you usually needed to manually specify the access modifier in languages like Java and C# in order to achieve encapsulation, which can result in verbose code.

Why do we need encapsulation? Think back to our getter and setter examples where we had to define getter and setter methods to read and modify our cat's 'name' field. Hypothetically, suppose our requirements change and we wanted to prefix all of our cat names with "Kitty". With encapsulation, we would only need to change our setter method. If, instead, we made our field 'public' and the name had to be manipulated directly through its instances, we would have to manually add the prefix to every direct manipulation of the 'name' field by an instance. As projects grow in complexity, this would not be desirable.

Method Hiding with 'overwrite'

Now that we have a firm understanding of access modifiers and encapsulation, let's return to our project. We need our 'Cat' class to render() differently from what the 'Animal' base class provides. The first step is to edit our 'Animal' base class to make the $element field 'protected' so that the field can be accessed by our derived classes (like 'Cat'):

            external $;

            module Animals
            {
                class Animal
                {
                    protected var $element = $(
                        """
                        <div class="animal">
                            <i class="icofont icofont-animal-cat"></i>
                        </div>
                        """
                    );

                    void render() {
                        $("#content").append($element);
                    }
                }
            }
            

Next, let's restore the render() method to 'Cat':

            external $;

            module Animals
            {
                class Cat : Animal
                {
                    string _name;

                    Cat(string name) {
                        _name = name;
                    }

                    void render() {
                        $element.attr("title", _name);
                        $("#content").append($element);
                    }
                }
            }
            

If you try to compile right now, you will get a compile error. The error itself should be quite descriptive:

[ ERROR ] JSPPE0252: `void Animals.Cat.render()' conflicts with `void Animals.Animal.render()'. Either create a method with a different name or use the 'overwrite' modifier

In this case, our derived class ('Cat') tried to define a method named 'render', but the base class ('Animal') already has a method named 'render'. Thus, we have a conflict. JS++ also suggests fixes for us: A) create a method with a different name, or B) use the 'overwrite' modifier.

Conceptually, both methods describe one concept: rendering to a web page. Thus, we might not want two different names to describe the same concept. Instead, we want to tell the JS++ compiler that this was intentional by using the 'overwrite' modifier:

            external $;

            module Animals
            {
                class Cat : Animal
                {
                    string _name;

                    Cat(string name) {
                        _name = name;
                    }

                    overwrite void render() {
                        $element.attr("title", _name);
                        $("#content").append($element);
                    }
                }
            }
            

In other object-oriented languages, this is known as "method hiding" or "method shadowing." The reason JS++ does this is to prevent potential mistakes and typos (especially for more complex classes). If we had two different concepts, such as 'Cat' rendering in memory while 'Animal' renders to the web page, we should not have the same method names in such a case.

Compile your code now. It should succeed. Open the web page, and you should now be able to hover your mouse over the cats again to see their names.

The 'super' Keyword

At this stage, we still have code duplication. Here's a look at the 'Animal' render() method:

            void render() {
                $("#content").append($element);
            }
            

And here's our 'Cat' render() method:

            overwrite void render() {
                $element.attr("title", _name);
                $("#content").append($element);
            }
            

Do you notice the duplication? What if we wanted to render to a different HTML element besides the one with the ID 'content' later? We would have to change the rendering code in all relevant classes!

Our 'Cat' class "extends" the concept of an 'Animal'. Likewise, our Cat's render() method "extends" the Animal's render() method by adding the HTML 'title' attribute so we can mouse over and see the name. However, besides that, our rendering logic is the same: add the element to HTML element with ID 'content'. We can do better. Let's "re-use" the rendering code from our 'Animal' class in our 'Cat' class:

            external $;

            module Animals
            {
                class Cat : Animal
                {
                    string _name;

                    Cat(string name) {
                        _name = name;
                    }

                    overwrite void render() {
                        $element.attr("title", _name);
                        super.render();
                    }
                }
            }
            

Compile, run, and observe the results. Now, no matter how our rendering logic changes, it'll be applied to all relevant classes. The key is the 'super' keyword. The 'super' keyword refers to the superclass of the current class. In this case, we use it to access the 'render' method of the 'Animal' class. Without 'super', we'd be calling the 'render' method of the current class - resulting in infinite recursion! (For example, using 'this' instead of 'super' will allow you to refer to the 'render' method of the 'Cat' class... but it'll result in infinite recursion.)

Abstraction

Thus far, we've learned about private, protected, and public fields and methods, but what about constructors? Open main.jspp and add the following code:

            import Animals;

            Cat cat1 = new Cat("Kitty");
            cat1.render();
            Cat cat2 = new Cat("Kat");
            cat2.render();
            Animal animal = new Animal();
            animal.render();
            

Compile and run.

Uh-oh! We've got three cats rendered to the page. At least when you hover over the last cat, it doesn't show a name. However, an 'Animal' is not a 'Cat' (but a 'Cat' is an 'Animal'). The reason we have three cat icons is because we have this in our Animal.jspp:

            protected var $element = $(
                """
                <div class="animal">
                    <i class="icofont icofont-animal-cat"></i>
                </div>
                """
            );
            

In other words, when our $element field is initialized, it is always initialized to a value that gives us a cat icon ("icofont icofont-animal-cat"). Instead, we may want to define a constructor on 'Animal' to parameterize this initialization. Let's change Animal.jspp so that this field is initialized in the constructor:

            external $;

            module Animals
            {
                class Animal
                {
                    protected var $element;

                    protected Animal(string iconClassName) {
                        string elementHTML = makeElementHTML(iconClassName);
                        $element = $(elementHTML);
                    }

                    public void render() {
                        $("#content").append($element);
                    }

                    private string makeElementHTML(string iconClassName) {
                        string result = '<div class="animal">';
                        result += '<i class="icofont ' + iconClassName + '"></i>';
                        result += "</div>";
                        return result;
                    }
                }
            }
            

I added access modifiers on all class members to make the code clearer. I also separated the construction of the HTML text into a separate function for clarity. Get into the habit of practicing the Single Responsibility Principle: all classes do one thing, all functions/methods do one thing. In the above code, our constructor does one thing: initialize the fields; our render() method does one thing: render to the web page; and, finally, our 'makeElementHTML' method does one thing: generate the HTML for our element. This leads to clean code, and JS++ was designed with clean code in mind so try to benefit from the design.

Another neat trick you may have noticed is to use ' (single quotes) to wrap HTML strings as shown in the code above. This is to avoid escaping the " (double quotes) used to surround the HTML attributes in our 'makeElementHTML' method.

You may have noticed that all the new access modifiers are different: protected constructor, public render(), and private makeElementHTML. Let's break this down from the most restrictive (private) to the least restrictive (public).

The reason 'makeElementHTML' is private is because it is an implementation detail. The only use of 'makeElementHTML' is inside our 'Animal' class. The 'Cat' class cannot access the method, and main.jspp cannot access the method (via instantiation). The 'Cat' class will never need to call 'makeElementHTML' — instead, the 'Cat' class inherits from the 'Animal' class. Via inheritance, the 'Cat' class will call the 'Animal' constructor. (We'll get to this shortly as the code currently cannot compile, but these concepts are more important to understand first.) As a consequence, the 'Cat' class will call 'makeElementHTML' via the 'Animal' class constructor, but it has no access to the method and is not able to call it directly. In this way, 'makeElementHTML' is an implementation detail of the 'Animal' class and is not exposed to any other portion of our code. This hiding of details that are irrelevant to other classes and code is known as "abstraction" in object-oriented programming.

As we mentioned in chapter 12, abstraction is the other fundamental pillar of object-oriented programming (OOP). For example, imagine a car. When you press the gas pedal on a car, you don't need to know how the specifics of the internal combustion engine works. The complexities of the inner workings are presented to you through a simplified interface: the gas pedal. Via abstraction, we are making complex systems simple, a desirable property of OOP.

After the private 'makeElementHTML' method, the next code with access privileges is the 'protected' constructor. Once again, the 'protected' access modifier is less restrictive than 'private' but not as permissive as 'public' (which has no access restrictions beyond scoping).

Specifically, what does it mean to make a constructor 'protected'? Recall that the 'protected' access modifier allows all members within the class to access but also includes all derived classes. Recall as well that instantiation of a class executes the code specified in the constructor. Logically, we're able to conclude that a protected constructor will mean that a class cannot be instantiated outside of specific contexts.

What are these specific contexts? The obvious case is that we cannot instantiate 'Animal' from main.jspp. If you try it right now, you'll get a compile error. However, since 'protected' can only be accessed from within the class itself and all derived classes, the intention of the protected constructor in our code is to restrict the class to inheritance only. Recall that the 'Cat' class cannot call the private 'makeElementHTML' directly; this method gets executed via the 'Animal' constructor during inheritance. During inheritance, the constructor gets executed just like in instantiation.

If you were to make the constructor 'private', you would essentially prevent instantiation and inheritance for the class. (Side Note: This is how the JS++ Standard Library 'System.Math' class is implemented.) Remember: the default access rule for everything except fields is 'public'. In other words, if we left the access modifier for our constructor unspecified, it would have defaulted to 'public'.

The 'super' keyword we used previously to access methods of the superclass refers to an instance of the superclass created during instantiation. When we instantiate 'Cat', we also instantiate 'Animal'. All relevant constructors will be executed up the chain, starting from the bottom of the chain. In our case, we execute the 'Cat' constructor first when 'Cat' is instantiated, and we move up the inheritance chain and execute the 'Animal' class constructor next. (JS++ uses a "unified type system" where 'System.Object' is the root of all internal types so the constructor for this class will also be called — but only if it's determined to be necessary and not a candidate for "dead code elimination" — but this is outside the scope of this chapter and will be discussed in the Standard Library chapters.)

Knowing that constructors get called during inheritance, we can now address the remaining problem in our code: you will notice that the code currently does not compile. The reason is because we've stopped using the implicit default constructor for the 'Animal' class when we defined a custom constructor.

Our 'Animal' constructor takes one parameter:

            protected Animal(string iconClassName) {
                string elementHTML = makeElementHTML(iconClassName);
                $element = $(elementHTML);
            }
            

We need to change the 'Cat' constructor code so that we specify how the superclass constructor should be called. We can do this once again via the 'super' keyword. The 'Animal' class wants to know the icon name of the type of animal we want to render. If you don't remember the name of the icon, I've included it here in the 'super' call for your convenience:

            external $;

            module Animals
            {
                class Cat : Animal
                {
                    string _name;

                    Cat(string name) {
                        super("icofont-animal-cat");
                        _name = name;
                    }

                    overwrite void render() {
                        $element.attr("title", _name);
                        super.render();
                    }
                }
            }
            

A function call on the 'super' keyword will execute the relevant constructor of the superclass. The 'super' call must always be the first statement because, semantically, the superclass's constructor will be executed before the constructor code of its derived classes.

Finally, we need to modify main.jspp to remove the instantiation of the 'Animal' class. Remember that since we made the 'Animal' constructor 'protected', we will be unable to instantiate 'Animal' from main.jspp anyway:

            import Animals;

            Cat cat1 = new Cat("Kitty");
            cat1.render();
            Cat cat2 = new Cat("Kat");
            cat2.render();
            

At this point, you can compile and the project should compile successfully. Once again, we should have the two cats:

Adding More Animals

Finally, we can add more animals.

Dog.jspp:

            external $;

            module Animals
            {
                class Dog : Animal
                {
                    string _name;

                    Dog(string name) {
                        super("icofont-animal-dog");
                        _name = name;
                    }

                    overwrite void render() {
                        $element.attr("title", _name);
                        super.render();
                    }
                }
            }
            

Dog.jspp is very much like Cat.jspp because a dog is also a domesticated animal that needs a name.

Panda.jspp:

            external $;

            module Animals
            {
                class Panda : Animal
                {
                    Panda() {
                        super("icofont-animal-panda");
                    }
                }
            }
            

Unlike Cat.jspp and Dog.jspp, Panda.jspp is significantly simpler. All the 'Panda' class does is inherit from 'Animal' and specify the icon to render. It has no name, and its render() method is exactly the same as Animal's since it doesn't have to add an HTML 'title' attribute on mouse over to display a name.

Rhino.jspp:

            external $;

            module Animals
            {
                class Rhino : Animal
                {
                    Rhino() {
                        super("icofont-animal-rhino");
                    }
                }
            }
            

Just like Panda.jspp, Rhino.jspp is also a very simple class. It just inherits from 'Animal' and has no need to set or render a name.

Finally, modify main.jspp to instantiate the new animals:

            import Animals;

            Cat cat1 = new Cat("Kitty");
            cat1.render();
            Cat cat2 = new Cat("Kat");
            cat2.render();
            Dog dog = new Dog("Fido");
            dog.render();
            Panda panda = new Panda();
            panda.render();
            Rhino rhino = new Rhino();
            rhino.render();
            

Compile the entire project like so:

$ js++ src/ -o build/app.jspp.js

Once again, on all platforms (Windows, Mac, and Linux), we are operating from the command-line so the compilation instructions should be the same for everyone. Also, it's completely unnecessary to specify the "compile order." It does not matter that 'Cat' depends on 'Animal' so, consequently, 'Animal.jspp' should be processed before 'Cat.jspp'. JS++ automatically resolves the compile order for you even for the most complex projects (e.g. with cyclic imports and complex dependencies). Just specify the input directories and let JS++ recursively find the input files and figure out the compilation order.

Open index.html in your web browser. The result should look like this:

Verify that your two cats have names, your dog has a name, but the panda and rhino should not have names when you hover your mouse over.

If everything works: congratulations! At this point, you may have noticed we can change our inheritance hierarchy as follows:

            Animal
            |_ DomesticatedAnimal
                |_ Cat
                |_ Dog
            |_ WildAnimal
                |_ Panda
                |_ Rhino
            

However, this is left as an exercise to the reader.

We've now covered three of the four fundamental concepts of OOP that we discussed in the chapter introducing classes and object-oriented programming: abstraction, encapsulation, and inheritance. The last fundamental pillar of OOP is polymorphism, which we'll cover in the next section.

Classes & OOP: Subtype Polymorphism

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

Subtyping describes type relationships, and subtype polymorphism enables operations defined for supertypes to be safely substituted with subtypes. Concretely, imagine the relation between a 'Cat' class and an 'Animal' class. (Remember: classes create data types in JS++.) In this case, within the context of type relationships, 'Cat' is the subtype of 'Animal' and 'Animal' is the supertype of 'Cat'. In simpler terms, 'Cat' "is a" 'Animal', but 'Animal' is not a 'Cat'. In theory, this means that all operations that apply to the 'Animal' data type should accept operating on data of type 'Cat'; however, the reverse is not true: operations defined for the data type 'Cat' would not safely be able to operate on data of type 'Animal'.

If you remember the code from the previous section, cats and dogs are domesticated animals with names. However, not all animals should be named so our 'Animal' class did not take a name parameter. Thus, while we could have defined and called a 'name' getter on an instance of 'Cat', we could not safely substitute the 'Cat' instance with an 'Animal' instance. In JS++, if you even try to do this, you will get an error.

Subtype polymorphism allows us to write code in a more abstract manner. For example, within the context of primitive types, a 'byte' represents numbers in the range of 0 to 255. Meanwhile, an 'int' represents numbers within a much larger range: -2, 147, 483, 648 to 2, 147, 483, 647. Therefore, we can substitute numbers of type 'byte' where numbers of type 'int' are expected:

        int add(int a, int b) {
            return a + b;
        }

        byte a = 1;
        byte b = 1;
        add(a, b);
        

Thus, we are able to express algorithms and functions more "generally" because we can accept a wider variety of data (categorized by data types) for any given algorithm or function.

It's important not to confuse subtyping with inheritance even though the concepts are closely related within object-oriented programming. Subtyping describes type relationships, whereas inheritance is concerned with implementations (such as extending the implementation of a base class with a derived class). Subtyping can apply to interfaces while "inheritance" cannot. This concept will become clearer in later sections when we cover interfaces.

As a starting point to practically understand subtyping, we can change main.jspp so that the data type of all of our variables becomes 'Animal' but we keep the instantiation of classes as the subtypes:

        import Animals;

        Animal cat1 = new Cat("Kitty");
        cat1.render();
        Animal cat2 = new Cat("Kat");
        cat2.render();
        Animal dog = new Dog("Fido");
        dog.render();
        Animal panda = new Panda();
        panda.render();
        Animal rhino = new Rhino();
        rhino.render();
        

Compile your code. It should compile successfully because, during instantiation, all data that is a subtype of 'Animal' can be assigned to a variable of type 'Animal'. In this case, 'Cat', 'Dog', 'Panda', and 'Rhino' data can all be safely assigned to 'Animal' variables.

However, there's a small "gotcha." Open index.html. You'll see all the animals rendered again, but, if you hover your mouse over any of the animal icons, you won't see any names! To understand why this occurs, we must understand static versus dynamic polymorphism, which will be explained in the next section. (In short, we actually specified we wanted "static" or compile-time polymorphism by using the 'overwrite' keyword on the 'render' method. Thus, we got the specified behavior.)

Classes & OOP: Static vs. Dynamic Polymorphism

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

Static polymorphism is polymorphism that occurs at compile time, and dynamic polymorphism is polymorphism that occurs at runtime (during application execution).

An aspect of static polymorphism is early binding. In early binding, the specific method to call is resolved at compile time. (JS++ also supports late binding via virtual functions which we will cover later.) Early binding is faster because there is no runtime overhead. Early binding is the default behavior and most common for JS++. If you want late binding, you have to explicitly specify it. Again, we'll cover late binding in a later section.

In our code, we specified the 'overwrite' modifier for our 'Cat' and 'Dog' class render() methods. This enabled method hiding, but it specifies early binding. Here's the code from Cat.jspp:

        overwrite void render() {
            $element.attr("title", _name);
            super.render();
        }
        

Later, when we changed the type of our cats to 'Animal' in main.jspp, the type of our cats was changed from 'Cat' to 'Animal'. You might say, "Yes, but we instantiated our cat objects using the 'Cat' class nonetheless." While this is true, it also means our cat variables can now accept data of any type satisfying the 'Animal' constraint (including 'Animal' itself if we didn't specify a protected constructor on 'Animal'). For example, this now becomes completely acceptable code:

        import System;
        import Animals;

        Animal cat1 = new Cat("Kitty");
        if (Math.random(1, 10) > 3) {
            cat1 = new Dog("Fido");
        }
        cat1.render();
        

Ignore the 'System' import, but it imports the Math.random() function. It's used for illustrating the example. I also purposefully kept the name of our variable as 'cat1' to illustrate the point. 'cat1' has type 'Animal'. Thus, all objects of type 'Animal' can be assigned to 'cat1' (including objects of type 'Dog').

If you actually compile, run the code above, and refresh sufficiently, you'll notice that your "cat" will sometimes be rendered as a dog.

As you can observe, when we have a type 'Animal', the data can be 'Cat' in our program or it can also randomly become a 'Dog' based on runtime random number generation. The random numbers are not generated at compile time. The random numbers are generated during application execution (runtime). Thus, from the compiler's perspective, if we are going to resolve the 'render' method, we are going to resolve it to the 'render' method of the user-specified type, 'Animal', because it is the most correct. Recall that in subtyping, all Cats and Dogs are Animals, but not all Animals are Cats and Dogs.

Thus, this should hopefully help you understand early binding and static/compile-time polymorphism.

Aside: Data Types as Specifications

Data types are also specifications. We are specifying what constitutes a correct program. For instance, you wouldn't specify a 'subtract' function to accept two parameters of type 'string'. In our case, if we wanted a cat, we should have specified the type 'Cat' rather than generalizing to 'Animal'. While the ability to express algorithms in more general terms is desirable, it may not always be correct.

Technically, the program is still type-correct. In both cases ('Cat' and 'Dog'), we have an object of type 'Animal'. It just happens that our 'Animal' was named 'cat1' so one potential fix for the code above may be to rename the variable to 'animal' or something similar to express our intent.

The other potential fix, if we want 'cat1' to always be a cat, is to restrict the data type to 'Cat' instead of 'Animal'. If you do this, you'll get a compile error because 'Dog' is not a subtype of 'Cat':

[ ERROR ] JSPPE5000: Cannot convert `Animals.Dog' to `Animals.Cat' at line 6 char 8 at main.jspp

In runtime polymorphism, the type is determined at runtime. For example, we can use the 'instanceof' operator to check the runtime data type. Change your main.jspp file and observe the result:

        import System;
        import Animals;

        external $;

        Animal animal = new Cat("Kitty");
        if (Math.random(1, 10) > 3) {
            animal = new Dog("Fido");
        }

        if (animal instanceof Cat) {
            $("#content").text("We have a CAT.");
        }
        else {
            $("#content").text("We have a DOG.");
        }
        

Keep refreshing and you should see that sometimes we have a 'Cat' instance and sometimes we have a 'Dog' instance. However, the types (and resulting messages) are determined at runtime — not compile time.

Classes & OOP: Upcasting and Downcasting

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

Now that we understand both subtyping and static versus dynamic polymorphism, we can learn about upcasting and downcasting.

Upcasting and downcasting is based on type relationships. In other words, if you have data of type 'Animal', you can "downcast" it to its subtype 'Dog'. Conversely, if you have data of type 'Dog', you can "upcast" it to its supertype 'Animal'. However, you cannot cast data of either type to 'int' because there is no type relationship between 'int' and 'Animal' or 'Dog'.

Since we are now equipped with an understanding of compile-time versus runtime polymorphism, and why and how the compiler resolved the 'render' method when the data type was specified as 'Animal', let's restore our main.jspp code:

        import Animals;

        Animal cat1 = new Cat("Kitty");
        cat1.render();
        Animal cat2 = new Cat("Kat");
        cat2.render();
        Animal dog = new Dog("Fido");
        dog.render();
        Animal panda = new Panda();
        panda.render();
        Animal rhino = new Rhino();
        rhino.render();
        

As you'll recall, this is the code that rendered all our animals, but we no longer got the animal names on mouse over. One way to remedy this is with a downcast:

        import Animals;

        Animal cat1 = new Cat("Kitty");
        ((Cat) cat1).render();
        Animal cat2 = new Cat("Kat");
        ((Cat) cat2).render();
        Animal dog = new Dog("Fido");
        ((Dog) dog).render();
        Animal panda = new Panda();
        panda.render();
        Animal rhino = new Rhino();
        rhino.render();
        

The syntax for a type cast is:

(type) expression

For example:

(int) 100

The reason there are extra parentheses in our revised main.jspp code is because we want the type cast to take precedence so that the cast occurs before the 'render' method is called. See the JS++ operator precedence table for more details.

If you compile and run the code now, you should see that the cats and dogs once again show their names when you hover your mouse over their icon.

To illustrate upcasting, we can also cast one of our cats to the 'Animal' type. Calling the 'render' method on this cat will mean it uses the 'Animal' class render() method which will not include the name:

        import Animals;

        Animal cat1 = new Cat("Kitty");
        ((Cat) cat1).render();
        Cat cat2 = new Cat("Kat");
        ((Animal) cat2).render();
        Animal dog = new Dog("Fido");
        ((Dog) dog).render();
        Animal panda = new Panda();
        panda.render();
        Animal rhino = new Rhino();
        rhino.render();
        

Notice that I changed the type of 'cat2' back to 'Cat' in order to illustrate upcasting. From there, I upcast 'cat2' to 'Animal'. If you compile the code now, you will notice the first cat ("Kitty") has its name shown on mouse over, but the second cat ("Kat") does not have the same behavior.

While we were able to resolve the correct 'render' method using casts, this is not the most elegant way to resolve the method. For example, if we had an array of 'Animal' objects, our loop would be nested with 'if' statements performing 'instanceof' checks and subsequent type casts. This is not ideal and leads to hard-to-read code. There is a more elegant way: virtual methods.

Classes & OOP: Virtual Methods

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

As we mentioned in the previous section, if we want runtime polymorphism, using casts can lead to unclean code.

By way of example, let's change our main.jspp code so that all our animals are inside an array. From there, we will loop over the array to render the animal. Open main.jspp and change the code to:

        import Animals;

        Animal[] animals = [
            new Cat("Kitty"),
            new Cat("Kat"),
            new Dog("Fido"),
            new Panda(),
            new Rhino()
        ];

        foreach(Animal animal in animals) {
            if (animal instanceof Cat) {
                ((Cat) animal).render();
            }
            else if (animal instanceof Dog) {
                ((Dog) animal).render();
            }
            else {
                animal.render();
            }
        }
        

Now our code is even less elegant than our original code that just instantiated the animals, specified the most specific type, and called render().

However, this code can be massively simplified until it becomes elegant. In fact, we can reduce the 'foreach' loop down to one statement. The answer: virtual methods.

Virtual methods enable "late binding." In other words, the specific method to call is resolved at runtime instead of compile time. We don't need all the 'instanceof' checks, all the casts, and all the 'if' statements as we saw in the code above. We can achieve something much more elegant.

First, open Animal.jspp and change the 'render' method to include the 'virtual' modifier:

        external $;

        module Animals
        {
            class Animal
            {
                protected var $element;

                protected Animal(string iconClassName) {
                    string elementHTML = makeElementHTML(iconClassName);
                    $element = $(elementHTML);
                }

                public virtual void render() {
                    $("#content").append($element);
                }

                private string makeElementHTML(string iconClassName) {
                    string result = '<div class="animal">';
                    result += '<i class="icofont ' + iconClassName + '"></i>';
                    result += "</div>";
                    return result;
                }
            }
        }
        

Save Animal.jspp. That's the only change we need to make.

However, just making our method virtual isn't enough. In Cat.jspp and Dog.jspp, we are using the 'overwrite' modifier on their 'render' methods. The 'overwrite' modifier specifies compile-time resolution. We want runtime resolution. All we have to do is change Cat.jspp and Dog.jspp to use the 'override' modifier instead of the 'overwrite' modifier. For the sake of brevity, I will only show the change to Cat.jspp but you need to make the change to Dog.jspp as well:

        external $;

        module Animals
        {
            class Cat : Animal
            {
                string _name;

                Cat(string name) {
                    super("icofont-animal-cat");
                    _name = name;
                }

                override void render() {
                    $element.attr("title", _name);
                    super.render();
                }
            }
        }
        

That's it. All we had to do was change modifiers. Now we can finally edit main.jspp so there is only one statement inside the loop:

        import Animals;

        Animal[] animals = [
            new Cat("Kitty"),
            new Cat("Kat"),
            new Dog("Fido"),
            new Panda(),
            new Rhino()
        ];

        foreach(Animal animal in animals) {
            animal.render();
        }
        

Compile your code and open index.html. Everything should work. Now we've been able to massively simplify our code and still get the expected behavior. Specifically, we reduced the code of our 'foreach' loop down from:

        foreach(Animal animal in animals) {
            if (animal instanceof Cat) {
                ((Cat) animal).render();
            }
            else if (animal instanceof Dog) {
                ((Dog) animal).render();
            }
            else {
                animal.render();
            }
        }
        
To this:
        foreach(Animal animal in animals) {
            animal.render();
        }
        

The reason we've been able to simplify our code so dramatically is because marking a method as 'virtual' signifies potential runtime polymorphism. Together with the 'override' modifier, the compiler knows we want late binding on the 'render' method so the "late" binding happens exactly when it's needed: the 'render' method will be resolved at runtime if and only when it needs to be resolved (inside the 'foreach' loop).

Classes & OOP: The 'final' Modifier

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

In the context of virtual methods discussed in the previous section, the 'final' modifier allows us to form an even more correct specification.

When applied to overridden methods, the 'final' modifier allows us to specify that this method override is the last and cannot be further overridden. This prevents subclasses from further overriding the method. In fact, it can be good defensive programming to use the 'final' modifier instead of the 'override' modifier. We can then only resort to the 'override' modifier when we need to subclass and the compiler gives us an error telling us that we cannot further override a method previously specified as 'final'. This can help us prevent unforeseen circumstances and potential bugs in complex code.

With that said, let's change Cat.jspp and Dog.jspp to use 'final' instead of 'override'. Once again, for the sake of brevity, I'll only be showing the changes to Cat.jspp:

        external $;

        module Animals
        {
            class Cat : Animal
            {
                string _name;

                Cat(string name) {
                    super("icofont-animal-cat");
                    _name = name;
                }

                final void render() {
                    $element.attr("title", _name);
                    super.render();
                }
            }
        }
        

If you compile the code and observe the result, you should see it behaves exactly as if we used the 'override' modifier.

The 'final' modifier can also be applied to a class. When the 'final' modifier is applied to a class, it means the class can no longer be subclassed. In other words, further inheritance is prevented. For example, try declaring 'Cat' as 'final' and try to subclass it from main.jspp:

        import Animals;

        class Kitten : Cat {}

        Animal[] animals = [
            new Cat("Kitty"),
            new Cat("Kat"),
            new Dog("Fido"),
            new Panda(),
            new Rhino()
        ];

        foreach(Animal animal in animals) {
            animal.render();
        }
        

If you try to compile this code, you'll get an error because 'Cat' is 'final' and cannot be subclassed:

[ ERROR ] JSPPE0163: Cannot inherit from final class `Animals.Cat'

Please remove the 'final' modifier from Cat.jspp and remove the 'Kitten' class from main.jspp. This was just a demonstration. Make sure your project compiles before moving to the next section.

Classes & OOP: Static Members and "Application-Global" Data

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

Up until now, all of the fields and methods that we've declared have belonged to class instances. Static members can also be added to a class. A static member is initialized at program start and is available to all instances of a class.

As an example, we might want to keep a count of the number of 'Animal' instances we have. This data should not be unique to one 'Animal' instance or another; it should be the same for all animals. Let's change Animal.jspp to achieve this using the 'static' modifier:

        external $;

        module Animals
        {
            class Animal
            {
                protected var $element;
                private static unsigned int count = 0;

                protected Animal(string iconClassName) {
                    string elementHTML = makeElementHTML(iconClassName);
                    $element = $(elementHTML);

                    Animal.count++;
                }

                public static unsigned int getCount() {
                    return Animal.count;
                }

                public virtual void render() {
                    $("#content").append($element);
                }

                private string makeElementHTML(string iconClassName) {
                    string result = '<div class="animal">';
                    result += '<i class="icofont ' + iconClassName + '"></i>';
                    result += "</div>";
                    return result;
                }
            }
        }
        

We've created a new field in the 'Animal' class: 'count'. It is initialized to zero at program start because it is marked 'static'. From there, on each constructor call of 'Animal' (e.g. via inheritance), we increment the 'count' static field by one using the ++ increment operator. We refer to the static field via 'Animal.count'. We actually don't need to qualify the name to this degree and can just use 'count' inside the class, but my intent was to show how 'count' should be accessed via the class name rather than an instance. Finally, we declared a getCount() method which returns the value of the static field.

Go to main.jspp and render this count to the web page using jQuery:

        import Animals;

        external $;

        Animal[] animals = [
            new Cat("Kitty"),
            new Cat("Kat"),
            new Dog("Fido"),
            new Panda(),
            new Rhino()
        ];

        foreach(Animal animal in animals) {
            animal.render();
        }

        $("#content").append("<p>Number of animals: " + Animal.getCount().toString() + "</p>");
        

Compile the project and open index.html. You should now see the count after your rendered animals:

While we've shown static field initialization at declaration, there is another way to initialize our static fields: static constructors. We can just as well change Animal.jspp to use a static constructor as follows:

        external $;

        module Animals
        {
            class Animal
            {
                protected var $element;
                private static unsigned int count;

                protected Animal(string iconClassName) {
                    string elementHTML = makeElementHTML(iconClassName);
                    $element = $(elementHTML);

                    Animal.count++;
                }

                static Animal() {
                    Animal.count = 0;
                }

                public static unsigned int getCount() {
                    return Animal.count;
                }

                public virtual void render() {
                    $("#content").append($element);
                }

                private string makeElementHTML(string iconClassName) {
                    string result = '<div class="animal">';
                    result += '<i class="icofont ' + iconClassName + '"></i>';
                    result += "</div>";
                    return result;
                }
            }
        }
        

Static constructors do not take any parameters, and they cannot have access modifiers applied. They will run at application start. In the code above, the 'count' static field was not initialized at declaration. Instead, we moved initialization of the 'count' field to the static constructor.

JS++ does not have a "global scope" like JavaScript does. Instead, variables that might have leaked into the global scope in JavaScript would instead be "file-scoped" in JS++ and will not be available outside the file it is declared. If you want "global variables, " you can achieve a safer subset known as "application-global data" using static members, and it's just as useful without the potential problems of global variables (e.g. unintentional leaks to other programs or libraries). Here's an example of how you can create application-global data using static members:

        module Application
        {
            class Config
            {
                public static string hostname = "127.0.0.1";
                public static unsigned int port = 80;
            }
        }
        

For more information on scoping, consult the JS++ documentation.

Classes & OOP: Abstract Classes and Methods

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

We have explored virtual methods and 'overwrite' (early binding) and 'override' (late binding) which allow us to define base implementations for a method and more specific implementations of the method in subclasses. However, what do we do if there is no relevant base implementation that makes sense? Consider a 'talk' method. While a 'Dog' will "woof" and a 'Cat' will "meow, " what will the 'Animal' base class do? Abstract classes and methods allow us to solve this problem.

When a class is declared with the 'abstract' modifier, it cannot be instantiated. Furthermore, it allows the class to have "abstract methods." Abstract methods are methods that don't define an implementation, and the implementation is left to the derived classes. The derived classes must implement all abstract methods when inheriting from an abstract class; otherwise, we'll get a compile error.

Let's start by making our 'Animal' class in Animal.jspp abstract and declaring an abstract 'talk' method:

        external $;

        module Animals
        {
            abstract class Animal
            {
                protected var $element;
                private static unsigned int count = 0;

                protected Animal(string iconClassName) {
                    string elementHTML = makeElementHTML(iconClassName);
                    $element = $(elementHTML);

                    Animal.count++;
                }

                public static unsigned int getCount() {
                    return Animal.count;
                }

                public virtual void render() {
                    $("#content").append($element);
                }

                public abstract void talk();

                private string makeElementHTML(string iconClassName) {
                    string result = '<div class="animal">';
                    result += '<i class="icofont ' + iconClassName + '"></i>';
                    result += "</div>";
                    return result;
                }
            }
        }
        

If we try to compile right now, we'll get compiler errors demanding that the subclasses of 'Animal' implement the 'talk' abstract method.

Let's start with Cat.jspp:

        import Externals.DOM;

        external $;

        module Animals
        {
            class Cat : Animal
            {
                string _name;

                Cat(string name) {
                    super("icofont-animal-cat");
                    _name = name;
                }

                final void render() {
                    $element.attr("title", _name);
                    super.render();
                }

                final void talk() {
                    alert("Meow!");
                }
            }
        }
        

We import 'Externals.DOM' because this module provides all the 'external' declarations for the DOM (Document Object Model) API for browsers. This allows us to use the 'alert' function which will pop up a message box with what we want the cat to say ("Meow!"). We could have also just declared 'alert' as 'external'. Notice that we used the 'final' modifier to override 'talk', but we could have just as well used 'override'.

We're going to implement Dog.jspp similarly, but dogs make a different sound:

        import Externals.DOM;

        external $;

        module Animals
        {
            class Dog : Animal
            {
                string _name;

                Dog(string name) {
                    super("icofont-animal-dog");
                    _name = name;
                }

                final void render() {
                    $element.attr("title", _name);
                    super.render();
                }

                final void talk() {
                    alert("Woof!");
                }
            }
        }
        

Now let's implement Panda.jspp. Pandas can bark, so let's make it bark:

        import Externals.DOM;

        external $;

        module Animals
        {
            class Panda : Animal
            {
                Panda() {
                    super("icofont-animal-panda");
                }

                final void talk() {
                    alert("Bark!");
                }
            }
        }
        

One last class to implement: 'Rhino'. Let's assume rhinos don't make a sound. It's perfectly fine to just override the abstract method and have it do nothing:

        external $;

        module Animals
        {
            class Rhino : Animal
            {
                Rhino() {
                    super("icofont-animal-rhino");
                }

                final void talk() {
                }
            }
        }
        

Notice that we didn't import 'Externals.DOM' either. We didn't need it. Our rhino doesn't talk so we don't need the 'alert' function for showing a message box.

At this point, your project should be able to compile without errors. However, our animals don't actually talk yet. We need some kind of event to trigger the animal talking. For example, we might want an animal to talk when we click on it. To achieve this, we need event handlers, and this is the subject of the next section.

Classes & OOP: Event Handlers

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

We've made our 'Animal' class abstract. We've declared an abstract 'talk' method and implemented this method in all subclasses of 'Animal'. However, our animals don't talk yet. We need a way to make animals do something when an event occurs. In this case, the "do something" we want is for the animal to talk and the "event" that needs to occur will be a user mouse click. We can do this with event handlers.

jQuery provides event handling, but we're going to define event handlers in an object-oriented manner. With abstract classes, you don't need to hook events to each individual class. Instead, you can attach an event to the abstract class and have it applied to all subclasses.

Modify Animal.jspp as follows:

        external $;

        module Animals
        {
            abstract class Animal
            {
                protected var $element;
                private static unsigned int count = 0;

                protected Animal(string iconClassName) {
                    string elementHTML = makeElementHTML(iconClassName);
                    $element = $(elementHTML);

                    attachEvents();

                    Animal.count++;
                }

                public static unsigned int getCount() {
                    return Animal.count;
                }

                public virtual void render() {
                    $("#content").append($element);
                }

                public abstract void talk();
                private void attachEvents() {
                    $element.click(talk);
                }

                private string makeElementHTML(string iconClassName) {
                    string result = '<div class="animal">';
                    result += '<i class="icofont ' + iconClassName + '"></i>';
                    result += "</div>";
                    return result;
                }
            }
        }
        

That's all you have to add. Compile the project and try clicking on the animals. You should see message boxes that pop up when you click on an animal (besides the rhino) and see the noise it makes:

Let's break down the code. We declared a private 'attachEvents' method. We made it 'private' because only the 'Animal' class needs it. In the 'Animal' constructor, we call the 'attachEvents' method. This should be straightforward at this point. Here's the code with new material; inside the 'attachEvents' method, we have this statement:

$element.click(talk);

As you'll recall, via inheritance, every subclass of 'Animal' will also have '$element' as data. This element is unique to each instance of a class. The '$element' field represents a jQuery object, as denoted by its $ prefix. We then use jQuery to attach an "event listener" to this '$element' that is unique to each instance.

Thus, when we instantiate 'Cat', 'Dog', 'Panda', and 'Rhino', we will execute the respective constructors for each, which start by executing a super() call to inherit from the 'Animal' class. 'Animal' in turn creates a unique '$element' for the class instance and attaches the 'click' event listener to the element. Thus, every one of our instances had an event attached to it even though only the abstract base class ('Animal') was modified.

Also, we passed the 'talk' method as a reference to 'click'. Both 'click' and 'talk' are functions. However, only 'click' uses the function call syntax (with parentheses). We didn't add parentheses after 'talk'. The reason is because we don't want 'talk' to immediately execute. We only want 'talk' to execute when a 'click' event occurs.

An event listener will wait until an event occurs. In this case, we attached a 'click' event so the event will be triggered when the user clicks the element with the mouse. Finally, we have to specify which method gets executed when the element is clicked:

$element.click(talk);

As you can see, we passed the 'talk' method as the "event handler." The event handler is the method that gets executed when the event gets triggered. In other words, we want the 'talk' method to execute when the element is clicked.

However, 'talk' is abstract. JS++ recognizes that we have an abstract class, and we're passing an abstract method. Since abstract methods cannot be executed, JS++ will resolve the correct method to execute. In this case, it will resolve to the respective subclass implementations of 'talk'.

Interfaces

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

As we learned in the chapter on subtype polymorphism, an operation defined for a supertype can be safely substituted with its subtypes. As a result, operations defined for 'Animal' objects can safely accept 'Cat' or 'Dog' objects.

Furthermore, we mentioned that you should not confuse subtyping with inheritance. Subtyping describes relationships between types, whereas inheritance is concerned with implementations. This distinction becomes clear with interfaces.

Interfaces are similar to the abstract classes and methods we just learned about, except that all the "methods" of an interface are abstract. An interface contains no implementations.

Interfaces specify types, but they do not specify implementations. Let's take a transportation analogy. You need to get from San Francisco to Los Angeles. You might not care how you get there, you just need a mode of transport. Interfaces don't define the "how" so the interface in this case would be the "mode of transport." The "how" would be implemented in classes like 'Train', 'Car', 'Airplane', or 'Bus'. As long as the "mode of transport" can move, it should meet your needs. However, you can't ride an abstract "mode of transport;" you need a 'Car', 'Train', 'Airplane', or 'Bus'.

To visualize these relationships:

        interface IModeOfTransport
        {
            void move();
        }

        class Car : IModeOfTransport
        {
            override void move() {
                // ...
            }
        }

        class Train : IModeOfTransport
        {
            override void move() {
                // ...
            }
        }

        class Airplane : IModeOfTransport
        {
            override void move() {
                // ...
            }
        }

        class Bus : IModeOfTransport
        {
            override void move() {
                // ...
            }
        }
        

Each concrete class moves differently. For example, a 'Car' will have a very different implementation for the 'move' method than an 'Airplane' because airplanes can fly.

From these relationships, you should be able to understand you can instantiate one of the classes above, such as 'Car', like this:

Car rentalCar = new Car();

Let's say you're developing a travel website. You want to provide the user several options of getting from San Francisco to Los Angeles. In this case, you might want to generalize the type:

IModeOfTransport transport = new Car();

Now, when the user selects a different option (other than 'Car'), you can easily change the type of data held in the 'transport' variable to an instance of 'Train', 'Plane', or 'Bus'.

However, you also recognize that you cannot get from San Francisco to Los Angeles by way of "mode of transport." You have to specify what kind of mode of transport. Thus, you should recognize this will result in a compiler error:

IModeOfTransport transport = new IModeOfTransport();

Therefore, we use interfaces only to specify types and type relationships. Interfaces do not provide implementations so they cannot be instantiated.

Equipped with this understanding, we can change our 'Animal' type relationships. First, let's start off with a very basic example. Some of our animals lack color. It's just a black-and-white web page right now. Let's add a bit of color.

Navigate to your OOP project's 'src/Animals/' folder containing Animal.jspp, Cat.jspp, Dog.jspp, etc. Inside this folder, create a new file named IColorizable.jspp. Inside IColorizable.jspp, let's enter this code:

        module Animals
        {
            interface IColorizable
            {
                void colorize();
            }
        }
        

The first thing you'll notice is that we prefixed our interface name with "I" (capital "i"). This is known as a naming convention. Naming conventions help us to name classes, interfaces, modules, functions, and variables that will be consistent with the names used by other programmers that join our team, other third-party libraries, and so on. In JS++, it is typical to prefix interface names with the letter "I" (capital "i").

Notice how we don't need the 'abstract' modifier. All method signatures inside an interface are considered abstract because implementations are not allowed inside an interface.

Next, we have to specify which classes share a relationship with IColorizable. For now, let's give only the 'Dog' class some color:

        import Externals.DOM;

        external $;

        module Animals
        {
            class Dog : Animal, IColorizable
            {
                string _name;

                Dog(string name) {
                    super("icofont-animal-dog");
                    _name = name;
                }

                final void render() {
                    $element.attr("title", _name);
                    super.render();
                }

                final void talk() {
                    alert("Woof!");
                }

                final void colorize() {
                    $element.css("color", "brown");
                }
            }
        }
        

Now, we have to call the colorize() method on our 'Dog' instance. Edit main.jspp:

        import Animals;

        external $;

        IColorizable fido = new Dog("Fido");
        fido.colorize();

        Animal[] animals = [
            new Cat("Kitty"),
            new Cat("Kat"),
            fido,
            new Panda(),
            new Rhino()
        ];

        foreach(Animal animal in animals) {
            animal.render();
        }

        $("#content").append("<p>Number of animals: " + Animal.getCount().toString() + "</p>");
        

Try to compile. You'll get an error:

[ ERROR ] JSPPE5034: Could not determine type for array literal. All elements in array literal must be the same, a mixture of primitive types, or descendants of the same base class at line 8 char 19 at main.jspp

The reason this happens is because the 'fido' variable is of type 'IColorizable'. Meanwhile, the array only accepts elements of type 'Animal'. If you'll recall, our 'Dog' class inherits directly from 'IColorizable' while our 'Animal' base class does not. Therefore, we cannot insert an object of 'IColorizable' directly into an array of type 'Animal'; otherwise, we would be able to perform unsafe operations as in JavaScript.

Notice, in the chart, that there is no type relationship between 'Animal' and 'IColorizable'.

There are multiple ways to fix this problem. We'll fix it by making all our animals colorizable. Edit Dog.jspp and remove the type relationship to 'IColorizable'. However, keep the method implementation for 'colorize'. You'll see why later. Here's a visualization of what you have to remove in Dog.jspp:

        import Externals.DOM;

        external $;

        module Animals
        {
            class Dog : Animal, IColorizable
            {
                string _name;

                Dog(string name) {
                    super("icofont-animal-dog");
                    _name = name;
                }

                final void render() {
                    $element.attr("title", _name);
                    super.render();
                }

                final void talk() {
                    alert("Woof!");
                }

                final void colorize() {
                    $element.css("color", "brown");
                }
            }
        }

Now open Animal.jspp and add:

        external $;

        module Animals
        {
            abstract class Animal : IColorizable
            {
                protected var $element;
                private static unsigned int count = 0;

                protected Animal(string iconClassName) {
                    string elementHTML = makeElementHTML(iconClassName);
                    $element = $(elementHTML);

                    attachEvents();

                    Animal.count++;
                }

                public static unsigned int getCount() {
                    return Animal.count;
                }

                public virtual void render() {
                    $("#content").append($element);
                }

                public abstract void colorize();

                public abstract void talk();
                private void attachEvents() {
                    $element.click(talk);
                }

                private string makeElementHTML(string iconClassName) {
                    string result = '<div class="animal">';
                    result += '<i class="icofont ' + iconClassName + '"></i>';
                    result += "</div>";
                    return result;
                }
            }
        }
        

Since our 'Animal' class is 'abstract', we don't need to "implement" the 'colorize' method. Instead, we just defer it a step further to the derived classes of 'Animal' by declaring the 'colorize' method as 'abstract'. Remember how we did not remove the 'colorize' method from the 'Dog' class? This is why. We've delegated the responsibility of implementing 'colorize' to the derived classes of 'Animal', but we've still been able to describe a type relationship between 'Animal' and 'IColorizable' where 'IColorizable' is a supertype of 'Animal'.

Now, we just need to add colors to the rest of our animals. I'll keep it brief. Here's a template for the kind of code you need to add to 'Cat.jspp', 'Panda.jspp', and 'Rhino.jspp':

        final void colorize() {
            $element.css("color", colorName);
        }
        

Replace 'colorName' with the color you want to make the animal. Make your cats "gold", pandas "black", and rhinos "silver".

Edit main.jspp:

        import Animals;

        external $;

        Animal[] animals = [
            new Cat("Kitty"),
            new Cat("Kat"),
            new Dog("Fido"),
            new Panda(),
            new Rhino()
        ];

        foreach(Animal animal in animals) {
            animal.colorize();
            animal.render();
        }

        $("#content").append("<p>Number of animals: " + Animal.getCount().toString() + "</p>");
        

Compile:

$ js++ src/ -o build/app.jspp.js

Open index.html. The result should look like this:

Classes & OOP: Generic Programming

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

In JS++, generic programming allows you to create classes, interfaces, and functions with type parameters, which allow classes and algorithms to be defined once for all applicable data types.

As we explored in Chapter 10, containers like dictionaries can be declared with a special syntax:

Dictionary<int> dict;

In particular, you will notice the data type 'int' inside the 'Dictionary' data type enclosed with angle brackets (<...>). The angle brackets are used to specify type arguments.

To understand this concept, imagine implementing the 'Dictionary' class yourself:

        class Dictionary
        {
            /* ... */
        }
        

Now, if we want our dictionary to contain string keys and integer values:

        class Dictionary
        {
            string[] keys;
            int[] values;
        }
        

However, what if we want string keys and string values?

        class Dictionary
        {
            string[] keys;
            string[] values;
        }
        

What if we want Boolean values? As you can see, we would have to constantly change the code in the class to support different value data types. Instead, we can use generics:

        class Dictionary<T>
        {
            string[] keys;
            T[] values;
        }
        

In the above code, we declared a generic class and 'T' is a type parameter. As a result, we can now only declare variables of Dictionary<T> by passing a type argument to 'T'. Type arguments can be any valid data type:

        Dictionary<int> intDict;
        Dictionary<string> stringDict;
        Dictionary<bool> boolDict;
        

It should be noted that generic programming, type parameters, and type arguments are compile-time concepts. Your type parameters and type arguments must be code that can be evaluated at compile time (such as data types like 'int').

Shorthands

As we explored in Chapter 10, dictionaries and arrays have special shorthands.

For arrays:

            Array<int> arr = new Array<int>([ 1, 2, 3 ]);
            // is the same as:
            Array<int> arr = [ 1, 2, 3 ];
            // is the same as:
            int[] arr = [ 1, 2, 3 ];
            

For dictionaries:

            Dictionary<int> dict = new Dictionary<int>({ "a": 1, "b": 2 });
            // is the same as:
            Dictionary<int> dict = { "a": 1, "b": 2 };
            

These shorthands are implemented at the language level. For user-defined generic classes, such shorthands are not available:

            class Foo<T> {}

            Foo<int> foo = new Foo<int>();
            

However, this can get repetitive. In our variable declaration, we have to type in 'Foo<int>' twice. Fortunately, JS++ provides a shorthand for this too via the 'auto' keyword:

            class Foo<T> {}

            auto foo = new Foo<int>(); // 'foo' has type 'Foo<int>'
            

The 'auto' keyword provides "local-variable type inference" where the variable type will be inferred based on the data type of the initializer expression. Since our variable initializer instantiates the class 'Foo' with type argument 'int', the data type for our variable will be inferred as 'Foo<int>'.

If you think the 'Dictionary' class name takes too long to type, 'auto' can also be used for dictionaries or even plain classes:

            import System; // provides the 'Dictionary' class

            class Foo {} // plain, non-generic class

            auto dict = { "a": 1, "b": 2 }; // 'dict' has type 'Dictionary<int>'
            auto foo = new Foo(); // 'foo' has type 'Foo'
            

Multiple Type Parameters

So far, we've learned how to declare a generic class with one type parameter, 'T'. ('T' is a naming convention and can be any valid identifier name. See the naming conventions documentation, which also provides guidance for generic programming.)

However, generic classes can actually be declared with any number of type parameters. For example, let's say we wanted to create a custom hash map class. Unlike our dictionaries, the hash map class should accept any data type for its keys and any data type for its values. Such a hash map class may look like this:

            class HashMap<K, V>
            {
                K[] keys;
                V[] values;
            }
            

Constraints

JS++ allows us to specify constraints for our generic class type parameters. Constraints will check that only a specific data type and its descendants are passed as type arguments.

Here's an example:

            class Animal
            {
            }

            class Lion : Animal {}
            class Tiger : Animal {}
            class Cup {}

            class Zoo<T: Animal>
            {
            }

            auto lionZoo = new Zoo<Lion>();
            auto tigerZoo = new Zoo<Tiger>();
            // auto cupZoo = new Zoo<Cup>(); // Error
            

As seen in our example, we restricted our 'Zoo' class to only accept type arguments that are 'Animal' types. (The constraint is expressed with the ':' colon syntax.) Thus, we can have the compiler check that we don't create a zoo full of 'Cup' objects.

'external' Type Argument

Now that we have an understanding of generic programming basics, there is one useful feature to understand.

One of the reasons JS++ is so useful is its compatibility with JavaScript. You can mix 'var' and 'function' with safe code seamlessly. Generic programming in JS++ extends this and allows you to specify 'external' as a type argument:

            var a = 1, b = false, c = "str";
            Array<external> arr = [ a, b, c ];
            

The concept may initially be difficult to wrap your head around, but it's useful. Essentially, you have an internal JS++ 'Array' with 'external' elements. You can use any of the JS++ methods defined for 'Array', but not the methods exclusive to JavaScript arrays. The elements are 'external' so any operation permitted for 'external' will be allowed on the individual elements.

Another example is the 'Dictionary' class:

            var a = 1, b = false, c = "str"; 
            Dictionary<external> = { "a": a, "b": b, "c": c };
            

JS++ dictionaries are not JavaScript objects. In JS++, dictionaries are just key-value pairs with string keys. You can't define a 'prototype' property on 'Dictionary<external>' or perform prototypal inheritance.

Covariance and Contravariance

Covariance describes subtyping relationships (such as "Cat" is "Animal"), and contravariance describes supertype relationships ("Animal" is an ancestor of "Cat").

Covariance and contravariance are important to understand in generic programming. Oftentimes, generic classes are used for specifying containers. Containers, like arrays, suffer from a problem like the following:

            import System;

            class Animal {}
            class Tiger : Animal {}

            class Pet : Animal {}
            class Dog : Pet {}
            class Cat : Pet {}

            Array<Dog> dogs = [ new Dog ];
            Array<Animal> animals = dogs; // error
            

If you compile the above code, you might encounter the following error:

[ ERROR ] JSPPE5000: Cannot convert `System.Array<Dog>' to `System.Array<Animal>' at line 11 char 24

The reason this happens is because type arguments are invariant by default. In other words, Array<T> != Array<E>; in this case, Array<Dog> != Array<Animal>. Yet, we know an array of dogs is an array of animals, but JS++ considers this operation potentially unsafe because you may then push a 'Cat' to the array. In order to safely permit this operation, you must specify the variance.

We know that 'Dog' descends from 'Animal'. Thus, to make the operation safe, all we have to do is specify that:

Array<descend Animal> animals = dogs;

The 'descend' keyword specifies "covariance." Covariant generic types are read-only. You cannot push a 'Cat' into the new 'animals' array. While you cannot modify the array, you can still iterate over it and read the values. For example, using a 'foreach' loop:

            import System;

            class Animal {}
            class Tiger : Animal {}

            class Pet : Animal {}
            class Dog : Pet {}
            class Cat : Pet {}

            Array<Dog> dogs = [ new Dog ];
            Array<descend Animal> animals = dogs;
            foreach(Animal a in animals) {
                    Console.log(a);
            }
            

We can extend this understanding further to deal with reads and writes. A mnemonic for generic programming is PECS (Producer Extends, Consumer Super). In other words, producers should accept covariant type relationships, and consumers should accept contravariant type relationships.

This is best illustrated with an example:

            import System;

            class Animal {}
            class Tiger : Animal {}

            class Pet : Animal {}
            class Dog : Pet {}
            class Cat : Pet {}

            class AnimalArray
            {
                    Array<Animal> animals = [];

                    void pushAllFrom(Array<descend Animal> src) {
                            foreach(Animal a in src) {
                                    animals.push(a);
                            }
                    }

                    void popAllInto(Array<ascend Animal> dst) {
                            for(int i = animals.length; i --> 0; ) {
                                    dst.push(animals.pop());
                            }
                    }
            }

            AnimalArray animals = new AnimalArray();
            Array<Dog> producer = [ new Dog ];
            animals.pushAllFrom(producer);
            Array<Object> consumer = [];
            animals.popAllInto(consumer);

            Console.log(consumer);
            

In our example, we create a custom array, 'AnimalArray'. The 'AnimalArray' encapsulates a private 'Array<Animal>' array for its internal representation. In addition, 'AnimalArray' provides two methods: 'pushAllFrom' and 'popAllInto'.

'pushAllFrom' is a producer so it uses a covariance relationship ("extends"). 'pushAllFrom' is a producer because it populates ("produces") the internal 'Array<Animal>' array. Consequently, it should accept all subtypes of 'Animal' since an array of 'Animal' objects should accept 'Dog' and 'Cat' objects. Thus, 'pushAllFrom' is able to accept an array of 'Dog' objects:

            Array<Dog> producer = [ new Dog ];
            animals.pushAllFrom(producer);
            

Unsurprisingly, covariant generic types in JS++ are read-only. We only need to be able to read over the array passed in as an argument to 'pushAllFrom'. We should not be able to write to it and modify the array by pushing a 'Cat' object into it. Otherwise, our 'producer' variable (of type 'Array<Dog>') will contain a 'Cat' object!

In contrast, 'popAllInto' is a consumer so it uses a contravariance relationship ("super"). 'popAllInto' is a consumer because it returns data to be consumed elsewhere. Therefore, it should use a contravariance relationship. As seen in the code example:

            Array<Object> consumer = []; 
            animals.popAllInto(consumer);
            

In the example, our consumer uses the superclass of all JS++ classes: System.Object (or just 'Object' if we're using partial qualification since we've imported the 'System' module). Since System.Object is a supertype of 'Animal', this is an acceptable relationship. If we changed our class to encapsulate a 'CatArray' or 'DogArray', it would likewise follow that the 'popAllInto' method should allow 'Cat' or 'Dog' objects to be written into an 'Array<Animal>' variable.

While covariant generic types are read-only, contravariant generic types are write-only. In fact, the 'popAllInto' method does mutate the input array by calling the 'pop' method on each iterated element.

Upcasting and Downcasting with Variance

With generic programming, the variance must be specified when upcasting and downcasting. For example, the following will fail:

            import System;

            class Parent {}
            class Child : Parent {}

            Array<Parent> obj = new Array<Child>(); // ERROR
            (Array<Child>) obj; // ERROR
            

However, if we specify the variance, the cast will succeed:

            import System;

            class Parent {}
            class Child : Parent {}

            Array<descend Parent> obj = new Array<Child>();
            (Array<Child>) obj;