Format:
if (condition) consequent else alternative
Example:
if (x < y) max = x else max = y
The alternative is optional:
if (!valid(input)) throw new Exception("invlid input")
There's a difference between conditional expressions and conditional commands. A conditional expressions returns a value, while a conditional command produces some side effect such as I/O or updating some variables.
In Java (and C) the conditional expression isn't used as much as the conditional command:
if (x < y) max = x else max = y // conditional command
max = (x < y)? x: y // conditional expression
Scala, on the other hand, only provides a conditional expression, but uses the syntax of a conditional command:
max = if (x < y) x else y // conditional expression
Of course it also works with commands:
if (x < y) max = x else max = y
Multi-way
selections can be achieved by nesting two-way selections:
if (income < 0)
System.err.println("income must be non-negative");
else if (income < 10000)
tax = 0;
else if (income < 20000)
tax = .2 * income;
else if (income < 35000)
tax = .3 * income;
else if (income < 50000)
tax = .5 * income;
else
tax = .75 * income;
Question: How much tax does a person making $15,000 pay? (Answer =
unknown.) $8000? (Answer = $800.)
if (income <
10000)
if (5000 < income)
tax = .1 * income;
else tax = .2 * income;
Both Java and C++ inherit the bizarre switch command from C. The syntax and semantics of the switch command are so awkward that they almost render the command unusable. Here is the syntax:
switch(EXPRESSION)
{
case EXPRESSION: COMMANDS
case EXPRESSION: COMMANDS
case EXPRESSION: COMMANDS
// etc.
default: COMMANDS
}
The expression in parenthesis, called the key, must produce an integer or integer subtype value when executed. The switch command contains one or more case clauses. Each case clause begins with an expression called a guard, followed by zero or more commands, called consequences. The last case clause traditionally begins with the reserved word "default". The list of commands following it are called alternatives:
switch(KEY)
{
case GUARD: CONSEQUENCES
case GUARD: CONSEQUENCES
case GUARD: CONSEQUENCES
// etc.
default: ALTERNATIVES
}
Semantically, the key is evaluated. The value of the key is compared to the value of each guard, starting with the topmost guard. When a match is found, all commands following the guard, including commands that follow subsequent guards, are executed. The defaule guard matches all keys. For example, here is a flowchart describing the semantics of a switch command with three case clauses guarded by expressions called GUARD1, GUARD2, and GUARD3, respectively:
Notice that if KEY == GUARD1 is false, but KEY == GUARD2 is true (i.e., not 0 or false), then CONSEQUENCES1 will be ignored, but CONSEQUENCES2 and CONSEQUENCES3 will be executed. This happens even if KEY == GUARD3 is false!
To prevent the consequences of subsequent case clauses from being executed, programmers often end each sequence of consequences with a break command. Break commands will be discussed later. Essentially, a break command causes control to exit the current control command and pass to the next command.
Here's an example of a switch command:
switch(op)
{
case '+': result = arg1 + arg2; break;
case '*': result = arg1 * arg2; break;
case '-': result = arg1 - arg2; break;
case '%': result = arg1 % arg2; break;
case '/':
if (arg2) result = arg1 / arg2;
else System.err.println("can't divide by
0");
break;
default: System.err.println("unrecognized operator " +
op);
}
We can only use this switch command if op happens to be declared as a character, since char is a subtype of int:
double arg1, arg2, result;
char op; // = operator used to combine arg1 & arg2
If we declare op as a string:
string op;
then we must use nested if commands.
Scala's match is a powerful improvement to switch.
Format:
key match {
case guard1 => branch1
case guard2 => branch2
case guard3 => branch3
// etc
case _ => default
}
var day = 3
day match {
case 0 =>
println("Sunday")
case 1 => println("Monday")
case 2 =>
println("Tueaday")
case 3 =>
println("Wednesday")
case 4 =>
println("Thursday")
case 5 =>
println("Friday")
case 6 =>
println("Saturday")
case _ => throw new
Exception("Invalid day")
}
day match {
case 0 | 1 => println("Weekend")
case 2 | 3 | 4 | 5 =>
println("Weekday")
}
var shape: Shape =
new Triangle(20, 10)
shape match {
case shape: Triangle => println(shape.area)
case shape: Rectangle => println(shape.area)
case _ => throw new Exception("Invalid
shape")
}
try
{ ... }
catch {
case e: NegativeAmountException => println("amount
must be positive")
case e: InsufficientFundsException =>
println("Insufficient funds")
case e: BadCommandException => println("Invalid
command, type help")
case _: Throwable => println("unknown error")
}
income match {
case
income if income < 100 => .1
* income
case
income if income < 1000 =>
.2 * income
case
income if income < 10000
=> .3 * income
case
_ => .1 * income
}
We can use a regular expression to extract matching elements from a string. (More on this later.)
val expPattern =
"""([0-9]+)\s*(\+|\*|-|/)\s*([0-9]+)""".r
def eval(exp: String) =
exp
match {
case
expPattern(arg1,
"+", arg2)
=> arg1.toInt
+ arg2.toInt
case
expPattern(arg1,
"-", arg2)
=> arg1.toInt
- arg2.toInt
case
expPattern(arg1,
"*", arg2)
=> arg1.toInt
* arg2.toInt
case
expPattern(arg1,
"/", arg2)
=> arg1.toInt
/ arg2.toInt
case
_ => throw new Exception("Invalid expression")
}