Cisco’s “Application Centric Infrastructure” – is it “Decisionless”?

Cisco has been promoting “Application Centric Infrastructure” as an alternative to Software Defined Networking (SDN).

I need to do more homework to appreciate the difference between SDN and ACI.

However, what struck to me was that ACI is about taking the policy out of forwarding path. As per my understanding of ACI, once a policy is set by the “intelligence” of APIC, hardware will take over forwarding.

This is strikingly similar to decision-less programming I have been advocating. Readers of this blog are aware that in decision-less programming, only I/O requires decisions. Business logic buried deep into FSMs of derived classes is implemented as policy look-up tables.

If my understanding of parallels so far is correct, I suppose ACI will have the same characteristics as decision-less programming:

  • There will be no “patchability” of policies. All the policies must be explicitly known, documented and implemented
  • The system will work predictably barring system level problems of running out of resources etc.
  • The system will be extremely fast
  • The system will be memory intensive
  • The system will require sophisticated input parsing
  • Testing of such systems will be trivial except at boundary conditions like array bound violations or at system level problems like thread lockups or disk overruns

2-D programming structures

I have been writing about my discomfort with “language-only” style of programming.

I often think in terms of a picture of actions rather than a compound statement. It is kind of difficult to explain to the “used to” programmers.

Interestingly, when I talk about “programming by pictures”, people think about “drag-and-drop” style of programming. I don’t mean that!

Then, a picture is better than a thousand words, right? Let us see some examples:
The first example is about nesting. The following code is expressed in 1-D:

	for (int i = 0; i < 36; i++) {
		for (int j = 0; j < 36; j++) {
			cout << screen[i][j];
		}
		cout << endl;
	}

This code can be easily expressed (and pre-processed unambiguously) with the following table like 2-D structure:

for (int i = 0; i < 36; i++)
for (int j = 0; j < 36; j++) cout << screen[i][j];
cout << endl;

Then there is execution exclusivity paths also. For example, you will never execute “if” and “else” paths together. Why do “languages” force them to list them in one line?

Take for example the following code:

			if (i%4 == 3) {
				if (j%4 == 3) {
					screen[i][j] = '+';
				} else if (i%12 == 11) {
					screen[i][j] = '-';
				}
			} else if (j%12 == 11) {
				screen[i][j] = '|';
			}
cout << "Hello world!" << endl;

can be expressed as:

if (i%4 == 3) else if (j%12 == 11)
if (j%4 == 3) screen[i][j] = ‘+’;
else if (i%12 == 11) screen[i][j] = ‘-‘;
screen[i][j] = ‘|’;
cout << "Hello world!" << endl;

So far as there are “drop-down” statements, use the new line, otherwise add a table.

Within a table,

  • A row header is a “nested”
  • A column header is “nester”
  • A cell represents the “intersection of conditions” and may contain any complexity of code
  • When the code can take alternate path in a “nester” or “nested”, add a column or a row respectively
  • Order of insertion into one-dimension is – left to right and top to bottom

The advantages are:

  • It suddenly becomes possible to correctly code and grasp a complex decision structure
  • Take for example the above code of ‘if’s. Just compare adding an action for (j%12 == 11) && (i%12==11) in the one-dimension code and 2D code!

The disadvantages or challenge are:

  • “do-while” may be a problem. We can introduce a convention of “do…while(condition)” in the column/row header
  • Labelled “break”s will work fine – rather, loop breaking becomes more evident
  • Case fall-through is not visualized using this scheme. But hey! do we really need it? Some switches don’t even have a switch-case – and most don’t have fall through
  • This approach is no silver bullet for understanding a 17 level deep indented code. This approach works for simpletons like me, who prefer the design absorbing decisions rather than the code

As you can see, I am not inventing a new language. I am just doing away with the tyranny  of one-dimension. A spreadsheet parser-cum-IDE should be very easy to write – FOR ANY (imperative/OO) PROGRAMMING LANGUAGE!

What do you say?

Dream like Turing Machines?

I am fairly ignorant about theoretical computer science.

Recently on Wikipedia I learned about a variant of Turing machines that actually generate decision trees instead of decision paths of the classical Turing machine. This new type of Turing machines are proven to be functionally equivalent of classical Turing machines. The article notes that such machines could be in theory more efficient than the classical ones. There ceases the interest of a theoretician.

I am not very sure about the theoretical soundness of my extension of this idea but I note it here nevertheless.

Loop Unrolling is a well-known strategy in Parallel computing. However, my readers know it very well that I am never against loops.

I don’t like the idea of decisions made by programs unless forced by environment.

If we evolve into an era of millions of simple (probably load and store) microprocessor cores on a chip, we can eliminate a lot of decisions. That means, no matter what the dynamic state of the program is, all the possible paths (or at least, breadth first paths) will be distributed as code to each core. Each core will have its stack and data (and global and text) segments.

There could be an “aha” trigger that finally selects a computation to be output.

Also, there could be other triggers (like need to I/O physically) that may trigger a “state swap” out of cores.

***

It is quite interesting from practical point of view.

It makes programming very simple to debug.

It is like our dreams – very less logic and a lot of loops.

Only when we wake up (“aha!”) or need an I/O (like hearing child crying or an earthquake sensed) we wake up and take a path that makes sense.

What do you say?

Summary

Looking  back, I have covered most topics that I wanted to discuss so far. The presentation has not gone exactly in the way planned. However, this is the time to offer the summary. This summary is written with a refactory point of view.

1. There are two types of decisions. Existence and environment decisions AND value decisions.

2. Most bugs and inflexible designs arise because decisions are spread in the design and the code.

3.  Make sure all “not”s are substituted by “if-else”s. Break decision clauses into larger chain of conditions if needed.

4. Convert all “equality” value “if-else if-else” into switch-cases. Split all “inequality” value “if-else if-else” into explicit rule base and simplify the implementation.

5. Once rule base is separated, try to convert as many switch-cases into function pointers as possible. This is going to separate “what” from “how” and will keep errors limited to  “what” parts. If you reach this step, most of your program will function without bugs and maintenance will start becoming easy.

6. If you are allowed to take a step further, see that the function pointer array that was generated in previous statement is nothing but class heirarchy. Convert them to sub classes. At this point you should see a collapse in the “how” code size and a drastic reduction in number of bugs.

7. If you are still allowed to take a step further, you are at door steps of aspect oriented programming. At this moment, you will be able to see environment variables changing the behavior across classes.  This is the time to write cross-cutting concerns and eliminate further bugs and induce further versatality in the code

8. Make sure your next code starts with these ideas followed rigidly. Introduce these ideas as check marks in code review. [e.g. “All possible if’s are converted into switches”, “all possible switches are converted into function pointers”, “all function pointers are converted into subclasses with inherited interface”,  …]

9. And yes, participate in language design issues and favor introduction of switch like control structures, associative arrays, late bindings, OO and AO – dependent on the context of the language.

My next series will be on testing algorithms. Until then, good bye!

“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;

}

Two types of “if”s and their ideal places

While I am writing this blog, I am also working full time. As I write the blog, my own ideas clarify against my experiences. This is one such evolutionary realization.

I am not sure whether I wrote earlier:

In ideal programming, decisions belong either to the top of the class hierarchy or at the leaf.

“if” statements come in two flavors: the “existential if” and the “value if”.

The existential if statements reflect hard realities of computation. “Whether the file pointer was NULL” or “Whether the malloc succeeded” or “Whether the password matched”. There is hardly anything one can do in the “else if” or “else” parts of this condition. These statements are the least attractive candidates to be pushed into a “switch-case” structures.

The value if statements are different. “Whether current temperature is within limits”, “Whether the passed parameter is an upper case letter”, “Whether this packet is of IPX protocol” and so on. Under normal circumstances, such statements also have a very strong “else if” or “else” parts. These are ideal candidates to convert into “switch-case” statements.

*****

As a matter of fact, a reasonably written C code will have 90% of the control statements as “value if” – and that is where the problem lies. A lot of these decisions are just type decisions – if the value of the variable a is x, the type must be y and z function needs to be called.

That is where OO starts scoring. In a good OO code, type decisions are minimal. The same situation would simply translate into: invoke z method of a. There is no decision to be taken!

This factor is often ignored when embedded systems programmers berate OO as slow because VFT lookup may slow down the program. However, we just now avoided a decision using OO and made the execution *faster*. In my experience, OO avoids a lot of decisions and hence compensates for the standard (and hence optimised) VFT lookup.

In one of the (scripting) OO codes I have written, only one existential if was needed per thousand lines of code – and no value if was ever needed in 20k line of code. The code ran 25% faster than its procedural counterpart. I am yet not factoring in the design flexibility OO brought with itself.