Friday 29 May 2009

Chunk 11 - Ternary operator and switch statement

Ternary operator

In Chapter 9 you learned to use the basic Processing operators and Chapter 10 introduced the Processing’s conditional structures. In this chapter we will take a look at the ternary operator, an operation of arity three, that is, an operation that takes three arguments, a boolean value and two operand expressions.

It is used as follows: variable = (condition)? expression_if_true : expression_if_false;

If the condition is true, the first value is assigned otherwise the second value is assigned to the variable.

The ternary operator is also referred to as conditional operator as it lets you assign a value to a variable based on a boolean decision; you might think of it as a short-hand alternative to an if...else statement.
The ternary operator is derived from early programming languages where storage and memory space was still an issue and this is why it seems a little cryptic and sometimes confusing at first sight. Programmers often need some time to get used to it and some even choose not to use it at all opting for the more verbose if...else syntax.
Let us consider the following example:

int aNumber = 7;
String aMessage;
if (aNumber%2 == 0 )
{
aMessage="The number is even";
}
else
{
aMessage="The number is odd";
}
println(aMessage);

Executing the code above will print “The number is odd” at the bottom of the Processing window as the condition (7%2 == 0) is not met. 7 modulo 2 returns 1 thus the condition is false and the code in the else statement is executed.

The equivalent of this statement using the ternary operator looks like the following:

int aNumber = 7;
String aMessage = (aNumber%2 == 0 ) ? "The number is even" : "The number is odd";
println (aMessage);
First, the condition is tested, in our case, is the modulo 2 of aNumber equal to 0 ? If the condition is true then the value before the “:” is returned and assigned to the variable aMessage otherwise the value after the “:” is returned and assigned to the variable aMessage.
The condition (7%2 == 0) evaluates to false as 7 modulo 2 returns 1, thus the String “The number is odd” is assigned to aMessage which is then printed at the bottom of the Processing window.
The difference between the ternary operator and the if...else statement is that the if...else syntax executes a block of code based on the condition it evaluates and the ternary or conditional operator is an expression which returns a value based on the condition it evaluates.
The advantage of the ternary operator is, that it let’s you assign a value to a variable based on a condition with a single line of code; however if you find yourself having trouble in understanding its syntax, you can still use the more long-winded if...else statement to achieve the same thing.
Let us consider another example to demonstrate the effectiveness of the ternary operator; let’s assume we want to write a program that draws 100 lines with alternating colours. To achieve this with an if...else statement, we could write the following program:
for(int i = 0; i < 100; i++)
{
if((i%2==0))
{
stroke(0);
}
else
{
stroke(255);
}
line(30, i, 80, i);
}
The same program, however, can be rewritten much more effectively in only 3 line of code by using the ternary operator:
for(int i = 0; i < 100; i++)
{
stroke((i%2==0) ? 0 : 255);
line(30, i, 80, i);}
The following is a screenshot of the result of the execution of the two programs; if variable i is even the stroke is black otherwise i is odd and the stroke is white.
As you have seen in the examples above, it is true that the ternary operator seems a little cryptic and difficult to use at first sight; however, once you get used to it, you’ll realize that it provides a very short and efficient way to assign a value to a variable based upon a boolean condition.
For further information about the ternary operator, please refer to either the Java language specification[1] or to the Processing API[2].
Switch Statement
The switch statement, like an if...else statement, is used to control the program execution based on the value of a control variable. The value of the control variable is compared to the value of a case selector, which is a constant value and needs to be of the same type as the control variable.

The switch statement is executed from top to bottom comparing the value of the control variable to each case selector. If the value of the control variable matches the value of a case selector, the program will enter that block of statements. The code after the case selector will be executed until a break command causes the execution to terminate the processing of the case block and exit the switch statement. If the value of the control variable does not match any of the case selectors the statements in the default case are executed.

The possible types of the control variable and the case selectors are the primitive types int, char, short or byte. Java 1.5 introduced a new type called the enum or enumerated type which is not supported by Processing at the time of writing. Unlike in other programming languages, a control variable of type String is not supported in Java and Processing. The common format of a switch statement is:

switch (control variable)
{
case selector:
statements;
break;

case selector:
statements;
break;

case selector:
statements;
break;

default:
statements;
break;
}
There can be as many cases as required and each case can contain as many statements as needed.

It is important to stress out that the break command is optional, but if you fail to give it, the execution flows through into the next case. Even if the selector and the control variable do not match the program will continue executing the code block for that case too. In addition, the program will continue checking all the remaining cases until it reaches the end of the switch statement which is a waste of computing time.

The default case at the end of the switch case is optional and the statements in this block are executed if no case selector matches the value of the control variable. The last break in the default case is unnecessary, but it is considered good practice to write it.

The switch statement is frequently used where a large number of conditions need to be tested; the switch statement is easier to debug, easier to read and easier to maintain than an equivalent series of if...else statements. Let us consider the following program using if...else statements:

/**
* Set up the scene
*/
void setup()
{
size(200, 200);
stroke(255);
background(0);
displayMessage();
}

/**
* Begin the drawing
*/
void draw()
{
//if the user presses a key
if(keyPressed)
{
//if the user presses l draw a line
if (key=='l')
{
background(0);
line(50, 100, 150, 100);
}
//if the user presses c draw a circle
else if (key=='c')
{
background(0);
ellipse(100, 100, 50, 50);
}
//if the user presses s draw a square
else if (key=='s')
{
background(0);
rect(75, 75, 50, 50);
}
//if the user presses r draw a rectangle
else if (key=='r')
{
background(0);
rect(75, 50, 50, 100);
}

//if the user presses t draw a triangle
else if (key=='t')
{
background(0);
triangle(75, 125, 75, 75, 150, 125);
}
//if the user presses any other key display a message
else
{
background(0);
displayMessage();
}
}
}

/**
* Display a message
*/
void displayMessage()
{
PFont font = createFont("Arial", 10);
textFont(font);
fill(204, 102, 0);
text("This example demonstrates the usage \nof a switch statement.", 10, 30);
text("Press the following keys to draw a shape:", 10, 60);
text("l --> line", 10, 90);
text("c --> circle", 10, 110);
text("s --> square", 10, 130);
text("r --> rectangle", 10, 150);
text("t --> triangle", 10, 170);
}

The program can be rewritten by using a switch statement like the following to achieve the same thing:

/**
* Set up the scene
*/
void setup()
{
size(200, 200);
stroke(255);
background(0);
displayMessage();
}

/**
* Begin the drawing
*/
void draw()
{
//if the user presses a key
if(keyPressed)
{
switch(key)
{
//if the user presses l draw a line
case 'l':
background(0);
line(50, 100, 150, 100);
break;
//if the user presses c draw a circle
case 'c':
background(0);
ellipse(100, 100, 50, 50);
break;
//if the user presses s draw a square
case 's':
background(0);
rect(75, 75, 50, 50);
break;
//if the user presses r draw a rectangle
case 'r':
background(0);
rect(75, 50, 50, 100);
break;
//if the user presses t draw a triangle
case 't':
background(0);
triangle(75, 125, 75, 75, 150, 125);
break;
//if the user presses any other key display a message
default:
background(0);
displayMessage();
break;
}
}
}

/**
* Display a message
*/
void displayMessage()
{
PFont font = createFont("Arial", 10);
textFont(font);
fill(204, 102, 0);
text("This example demonstrates the usage \nof a switch statement.", 10, 30);
text("Press the following keys to draw a shape:", 10, 60);
text("l --> line", 10, 90);
text("c --> circle", 10, 110);
text("s --> square", 10, 130);
text("r --> rectangle", 10, 150);
text("t --> triangle", 10, 170);
}

Let us analyse the program and especially the switch statement in detail: First the setup() method initializes the scene by creating a processing window of size(200, 200), setting the stroke and the background colour. Then, the method displayMessage() is called to display a message to the user how to use the program. The result is the following screenshot:


Figure 1: Screenshot of the switch example program.

Next, the draw method is executed in a loop, which is the default behaviour if there is no noLoop() command specified. The boolean system variable keyPressed is true if any key is pressed and false if no keys are pressed[3], thus if the user presses a key, the program enters the switch statement. The system variable key always contains the value of the most recent key on the keyboard that was used (either pressed or released)[4] which serves as control variable for the switch statement.

Let us assume the user presses the ‘c’ key; the control variable key takes the value of char ‘c’. The switch statement is executed from top to bottom, comparing the value of the control variable to the constant value of each case selector. If the value of the case selector is logically equal to the value of the control value (control variable == case selector) then the statements after the case selector are executed. In our example, the user presses the ‘c’ key, which causes the following statements to execute:

case 'c':
background(0);
ellipse(100, 100, 50, 50);
break;

The background is set to black and an ellipse, in our case a circle, is drawn on the canvas. The break command causes the program to exit the switch and as the program is executed in a loop, it waits for another key to be pressed.

Figure 2: Screenshot of the switch example program after the user pressed the ‘c’ key.

If the user presses any other key, than the one specified by the case selectors the switch statement jumps to the default case, resetting the background and displaying the message how to use the program.

default:
background(0);
displayMessage();
break;


Figure 3: Screenshot of the switch example program executing the ‘default’ case.

A problem that may arise is that the user, inadvertently, has the caps lock on, causing the program to display the message how to use the program whatever key is pressed. To circumvent that issue, we can add the upper case characters to the case selectors, letting the cases simply fall through, like in the following example:

/**
* Set up the scene
*/
void setup()
{
size(200, 200);
stroke(255);
background(0);
displayMessage();
}

/**
* Begin the drawing
*/
void draw()
{
if(keyPressed)
{
//if the user presses a key
switch(key)
{
//if the user presses l draw a line
case 'L':
case 'l':
background(0);
line(50, 100, 150, 100);
break;
//if the user presses c draw a circle
case 'C':
case 'c':
background(0);
ellipse(100, 100, 50, 50);
break;
//if the user presses s draw a square
case 'S':
case 's':
background(0);
rect(75, 75, 50, 50);
break;
//if the user presses r draw a rectangle
case 'R':
case 'r':
background(0);
rect(75, 50, 50, 100);
break;
//if the user presses r draw a triangle
case 'T':
case 't':
background(0);
triangle(75, 125, 75, 75, 150, 125);
break;
//if the user presses any other key display a message
default:
background(0);
displayMessage();
break;
}
}
}

/**
* Display a message
*/
void displayMessage()
{
PFont font = createFont("Arial", 10);
textFont(font);
fill(204, 102, 0);
text("This example demonstrates the usage \nof a switch statement.", 10, 30);
text("Press the following keys to draw a shape:", 10, 60);
text("l --> line", 10, 90);
text("c --> circle", 10, 110);
text("s --> square", 10, 130);
text("r --> rectangle", 10, 150);
text("t --> triangle", 10, 170);
}

If the user has the caps lock on and presses the ‘c’ key, the value of the control variable has the value ‘C’; when the switch statement is executed it will jump to the case 'C': selector and as there are no statements and no break command, the switch statement falls through the case 'C': selector and will execute the statements in that case.

As you have seen from the examples above, the switch statement is more structured and more readable than the equivalent if…else statement. In general, it is considered good programming practice to use a switch statement to replace large series of if...else statements when ever possible.

For further information about the switch statement, please refer to either the Java language specification[5] or to the Processing API[6].



[1] “Expressions – 15.25 Conditional Operator ? :”, available online: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#290293 [accessed 28 May 2009]
[2] “?: (conditional) \ Language (API) \ Processing 1.0”, available online: http://www.processing.org/reference/conditional.html [accessed 28 May 2009]
[3] “keyPressed \ Language (API) \ Processing 1.0”, available online: http://www.processing.org/reference/keyPressed.html [accessed 28 May 2009]
[4] “key \ Language (API) \ Processing 1.0”, available online: http://www.processing.org/reference/key.html [accessed 28 May 2009]
[5] “Blocks and Statements - 14.11 The switch Statement”, available online: http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.11 [accessed 28 May 2009]

[6] “switch() \ Language (API) \ Processing 1.0”, available online: http://processing.org/reference/switch_.html [accessed 28 May 2009]

No comments: