BDR is cool, but it's a bit chaotic. First, the buggles giggle in any directions, and then the code you had to write to let them move is rather difficult to read. Here is a new BDR world where the buggle will dance a gentle circle. We will benefit this tranquillity to clean up a bit our code thanks to the new constructs we will introduce.
switch
conditionals[/!][!scala]Pattern matching[/!]The hardest part of previous code is certainly the conditional cascading. Somewhere in your code, you certainly had something similar to:
if ([!java]getIndication() == 'R'[/!][!scala]readMessage() == "R"[/!]) {
right();
forward();
} else if ([!java]getIndication() == 'L'[/!][!scala]readMessage() == "L"[/!]) {
left();
forward();
} else if ([!java]getIndication() == 'I'[/!][!scala]readMessage() == "I"[/!]) {
back();
forward();
/* other else if */
} else {
finished = true;
}
When you review this code, it may not be clear at the first glance that it
is simply a choice with 4 branches depending on the value of
[!java]getIndication()[/!][!scala]readMessage()[/!].
To improve this, we will use a
[!java]switch
construct, which Java syntax is the following:[/!]
[!scala] pattern matching, which is a very powerful construct that greatly generalizes
the if
. It is arguably one one the major advantages of Scala when compared to languages such as Java or python.
It is not new either, as other languages such as OCaml or Haskell offer this feature since long, but still.
It's really cool![/!]
switch (expression) { case firstValue: whatToDoIfExpressionEqualsFirstValue(); break; case secondValue: whatToDoIfExpressionEqualsSecondValue(); break; case thirdValue: whatToDoIfExpressionEqualsThirdValue(); break; /* as much similar cases as you want */ default: whatToDoIfExpressionDoesNotEqualsAnySeenValues(); }
Observe that each branch of a switch must be ended by a
break
. If you forget this, the machine keeps going and execute
the next branch in the list after the branch it jumped to. There is even
some rare cases where this behavior reveals helpful.
It is then possible to rewrite previous BDR code in a cleaner way using the switch construct:
switch (getIndication()) { case 'R': right(); forward(); break; case 'L': left(); forward(); break; case 'I': back(); forward(); break; default: return; }[/!] [!scala]
expression match { case possible value => instructions case other value => other instructions case another value => yet another instructions case _ => default instructions }
The expression provided before the keyword match
, and then
the branches are evaluated one after the other until we find one which value provided
between case
and =>
is equal to the expression's value.
The _
symbol acts as a wildcard, so the _
branch always matches.
Here is an example where a variable name
is matched.
name match { case "Martin" => println("Hello Martin, how are you?") case "Gerald" => println("Hey Gerald! How are you doing?") case _ => println("Welcome stranger.") }
It is possible to have more than one instruction per branch, and merge branches when the values are separated by a | symbol.
name match { case "Martin" | "Gerald" => println("Hello "+name+", how are you?"); openTheDoor() case _ => println("Hello stranger. Please do not pass."); lockTheDoor() }
You can even add guards to your branches. These are extra conditions that must be respected for the branch to get applied. This is handy if you want match on value ranges, as follows.
age match { case i if i<10 => println("Hey kid!") case i if i<20 => println("Hey dude!") case i if i<30 => println("Hello young man") case _ => println("Hello Sir") }
Note that there is no need to check whether the value is higher than 10 on the second line because the first matching branch is used. So, if the second branch gets evaluated, then the first one did not match.
Finally, it is possible also to match several variables in one shoot!
(x,y) match { case (0,0) => println("that's the origin") case (_,0) => println("On the ordinate") case (0,_) => println("On the abscissa") case (_,_) => println("Some random point") }
I told you that scala's pattern matching is very powerful! I actually love this feature!
[/!][!java|scala]Apply the improvement we just saw to rewrite your buggle code with the following dance steps. [/!] [!python]Let's teach a new dance step to the buggles. It is slightly more complex but actually better looking. Beside of that, that's the same old story.[/!] Note that we can now move up to 6 cells in one dance step.
Message | What to do |
[!java]'R'[/!][!scala|python]"R"[/!] | Turn right and move one step forward |
[!java]'L'[/!][!scala|python]"L"[/!] | Turn left and move one step forward |
[!java]'I'[/!][!scala|python]"I"[/!] | Turn back and move one step forward |
[!java]'A'[/!][!scala|python]"A"[/!] | Move one step forward |
[!java]'B'[/!][!scala|python]"B"[/!] | Move two steps forward |
[!java]'C'[/!][!scala|python]"C"[/!] | Move three steps forward |
[!java]'D'[/!][!scala|python]"D"[/!] | Move four cells forward |
[!java]'E'[/!][!scala|python]"E"[/!] | Move five cells forward |
[!java]'F'[/!][!scala|python]"F"[/!] | Move six cells forward |
[!java]'Z'[/!][!scala|python]"Z"[/!] | Move one step backward |
[!java]'Y'[/!][!scala|python]"Y"[/!] | Move two steps backward |
[!java]'X'[/!][!scala|python]"X"[/!] | Move three steps backward |
[!java]'W'[/!][!scala|python]"W"[/!] | Move four cells backward |
[!java]'V'[/!][!scala|python]"V"[/!] | Move five cells backward |
[!java]'U'[/!][!scala|python]"U"[/!] | Move six cells backward |
(anything else) | Stop dancing. |
When you program works again, proceed to next exercise.