“value if”s to “switch-case”s – ideas and issues

*****

Then then a lot of questions arise. The first one is: “Why should we have “switch-case” instead of “if”s?”
From earlier postings, we have made it clear that the flow of “switch-case” is much easier to understand than that of “if-elseif-else” for a number of reasons.

1. “Switch-case” announces its concern first unlike “if-else if-else” where parameters of decisions are unknown till you read each phrase

2. “Switch-case” has minimal and uniform logic unlike “if-else if-else” where unrestricted strings of logic contain a lot of surprise and inflexibility for the code maintainer

3. “Switch-case” organize ANDing and ORing as code flow itself and keep “apparent” logic simple unlike “if-else if-else” where flow of code through unrestricted strings of logic has to be reconstructed in the maintainer’s brain

4. “Switch-case” uses “default”, which can be expressed in the problem domain language easier than De Morgan Law firing “not”s

5. “Switch-case” logic substituting “value if”s usually point to higher chances of abstraction such as pushing the logic into the caller function and to higher cohesion

*****

The second question is: “Are all “if”s are convertible to “switch-case”s?”

The answer is obviously “Unfortunately, Not”. For example, how do you convert the following into a “switch-case” statement?

if (temperature == 0 ) {

printf ( “Kelvin rules”);

} else if (temperature < 237) {

printf (“Water is frozen”);

} else if (temperature < 337) {

printf (“Steam is liquid”);

} else {

printf (“Ice is vapor”);

}

The only way to introduce a switch-case statement here is to set some state variable somehow and then switch. If your library provider does not set up temperature range state, you have no choice but to implement “if-else if-else” chained rule base and then take a decision based on switch-case.

Interestingly, in this case, you could also eliminate the switch-case altogether and have rule base nicely detached from execution logic. For example,

/* in the physical chemist’s file */

enum state = {zero, ice, water, steam};

char *message[4] = { “Kelvin rules”, “Water is frozen”, “Steam is liquid”, “Ice is vapor” };

enum state my_state;

if (temperature == 0 ) { my_state = zero;

} else if (temperature < 237) {

my_state = ice;

} else if (temperature < 337) {

my_state = water;

} else {

my_state = steam;

}

/* In the plant engineer’s file */

enum state my_state;

printf (message[(int)my_state]);
Where is the saving? Try adding the fact that if the tempearture exceeds “Planck’s temperature”, the message should read “Planck rules”. You will realize that even with the same “if-else if-else”, the concerns are separated.

Now assume that in our language, we have a relational switch statement that can switch based on given entities, the physical chemist’s file will look like this:

/* in the physical chemist’s file */

enum state = {zero, ice, water, steam};

char *message[4] = { “Kelvin rules”, “Water is frozen”, “Steam is liquid”, “Ice is vapor” };

enum state my_state;

switch (temperature) {
case == 0 : my_state = zero;

case < 237: my_state = ice;

case < 337: my_state = water;

case < PLANCK_T: my_state = vapor;

default: my_state = planck;

}

Suddenly the code starts looking like a physical chemist’s handbook and we have not changed the plant engineer’s code just like the previous case!

Unfortunately, C does not support relational switch as stated above! AFAIK no other language support such a statement either.

That is why I love Tcl. The only language I know that lets user define his/her own control structures. Expect is perhaps the most well-known control structure defined later than its language.

Another example is from the design pattern book from Go4. [The code appears as a sample code for Singleton pattern. Copied here for review.]

MazeFactory* MazeFactory::Instance () {

if ( _instance == 0 ) {

const char* mazeStyle = getenv(“MAZESTYLE”);

if ( strcmp (mazeStyle, “bombed”) == 0 ) {

_instance = new BombedMazeFactory;

} else if ( strcmp (mazeStyle, “enchanted”) == 0) {

_instance = new EnchantedMazeFactory;

}
// … other possible subclasses

} else {

_instance = new MazeFactory;

}

return _instance;

}

A C programmer has to live with this implementation. However, Tcl programmer can split the rule and the implementation, leaving implementation to be eval’ed later.

# Rule base

set mazeConstructor(“bombed”) “BombedMazeFactory”

set mazeConstructor(“enchanted”) “EnchantedMazeFactory”

set mazeConstructor(“default”) “MazeFactory”

# Implementation

set _instance $mazeConstructor(“default”)

if { [ info exists [mazeConstructor([$env(MAZESTYLE)]) } {

    set _instance [ new $mazeConstructor($env(MAZESTYLE)) ]

}

Yet another comparison could be:

if ( hare.distance == FULL_DISTANCE )

    declareWinner(hare);

else if (tortoise.distance == FULL_DISTANCE )

    declareWinner(tortoise); 

This scenario arises when a number of variables are compared against a constant value. In that sense it is “variable switch” rather than traditional “value switch”.

If we could have such a variable switch, our code could look like:

variableSwitch (FULL_DISTANCE) {

case hare.distance: declareWinner(hare);

                                   break;

case tortoise.distance: declareWinner(tortoise);

                                   break;

}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s