Image by Oliver | Some Rights Reserved

Sometimes the simplest of things elude us. We miss the forest for the trees. Or, we come up with what seems to be an elegant solution to a coding problem, only to realize (or, in my case, have pointed out, on Reddit) that we have not only done something abysmally stupid, but did so instead of using the programming 101, most basic, back-to-the-fundamentals solution to what has to be one of the oldest problems in programming history. Doh!

In my recent post about Building a Useful, Interactive, and Extensible .NET Console Application Template for Development and Testing, I posted some code where I implemented the interactive loop for a console like this:

The Fatally Flawed, Dumb IO Loop for a Console Application:

class Program { static void Main(string[] args) { Console.Title = typeof(Program).Name; // We will add some set-up stuff here later... Run(); } static void Run() { // Get input from the user: var consoleInput = ReadFromConsole(); if(string.IsNullOrWhiteSpace(consoleInput)) { // Nothing was provided - start over: Run(); } try { // Execute the command: string result = Execute(consoleInput); // Write out the result: WriteToConsole(result); } catch (Exception ex) { // OOPS! Something went wrong - Write out the problem: WriteToConsole(ex.Message); } // Always return to Run(): Run(); } static string Execute(string command) { // We'll make this more interesting shortly: return string.Format("Executed the {0} Command", command); } public static void WriteToConsole(string message = "") { if(message.Length > 0) { Console.WriteLine(message); } } const string _readPrompt = "console> "; public static string ReadFromConsole(string promptMessage = "") { // Show a prompt, and get input: Console.Write(_readPrompt + promptMessage); return Console.ReadLine(); } }

If you take a good look at the Run() method, you will see the recursion happening there.

I’m not sure why I thought this was a good way to do this, beyond that it seemed elegant, and I really hadn’t thought things through (or thought much at all. Because…programming 101. Literally.

Recursion Consumes Stack Space (and Hence, Memory)

I know this. So I’m not sure why I thought it would be Ok to use recursion in an unbounded context like this.

Recursively calling a method incurs a memory cost, as each time the method calls itself, what is essentially a copy of all the variables, parameters and memory addresses used by the function are pushed onto the stack as a stack frame.

Understanding the details of this is less critical than understanding the over-arching concepts. For more information on Stacks, Heaps, and Recursion, see Explanation of the Stack, the Heap, and Recursion Leading to Stack Overflow at Joel in point form.

While realistically, most who might use a .NET console application such as this example is derived from are unlikely to actually run into a stack overflow situation, it is still simply poor design. Or the programmer not thinking at all.

In this case, it was the latter.

Of While Loops and Ball Bearings

The section heading from the previous post in which the code above appears is, literally “Console Basics – The Interactive Input and Output Loop.”

The correct, and for most introductory programming students, obvious solution was right there in the section title.

A while loop.

The Run() method in the above code can (and SHOULD HAVE BEEN) written as follows:

The Fundamental, Time-Tested Way to write the Interactive Loop for a Console Application:

static void Run() { while (true) { var consoleInput = ReadFromConsole(); if (string.IsNullOrWhiteSpace(consoleInput)) continue; try { // Execute the command: string result = Execute(consoleInput); // Write out the result: WriteToConsole(result); } catch (Exception ex) { // OOPS! Something went wrong - Write out the problem: WriteToConsole(ex.Message); } } }

This code continues the IO loop until the user breaks manually by exiting the application. While we could get just a little more clever, in introduce some method return values which might cause the loop to exit, nothing like that was needed for this particular case.

This is such a basic thing, I am embarrassed for having missed it. I myself have used examples from introductory tutorials which use this very mechanism to operate an interactive console.

Occam’s Razor and Ball Bearing Complication

Sometimes in life, and especially in programming, we tend to allow “clever” to be the enemy of “good.” We seek solutions to coding problems which allow us to feel accomplished, or which allow us to utilize some new shiny thing we have discovered, and we loose sight of the fact that we are really just seeking to solve a problem.

And often, that problems has been solved, over and over again, long before.

“The Simplest Answer is Usually Correct.”

This common paraphrase of Occam’s Razor is completely applicable here. While not wholly accurate, it represents a concise statement of what should have been my reasoning when putting together my code.

From the Wikipedia entry, we find a few more formal versions of the philosophical construct known as Occam;s Razor:

“Among competing hypotheses, the one with the fewest assumptions should be selected”

Another, as stated by Aristotle in Posterior Analytics:

“We may assume the superiority ceteris paribus [all things being equal] of the demonstration which derives from fewer postulates or hypotheses.”

As programmers, we often tend towards what we think are elegant solutions. We like to plan for cases that might happen. We like to try using “innovative” means to solve problems.

I often fall victim, in programming and in life, to what I call the “Complicate a Ball Bearing” syndrome. A good friend of mine, a non-programmer, often made the observation that he can “Complicate the shit out of a ball bearing.” Meaning, given a simple life problem and several possible solutions, he always managed to choose the most convoluted path to resolution, often creating a bigger mess than what he had started with.

In my case here, re-implementing the code to utilize the good old while loop was trivial. Figuring out why I didn’t exercise some good judgment, and employ the solution any student of introductory programming would use without even thinking? That’s complicated.

In Closing

The code for the Extensible Console Application project has been updated and pushed to Github. The previous blog post has been updated, acknowledging this idiocy (because that’s just how I roll, dammit. Public self-flagellation is good for the soul.

Additional Resources and Items of Interest

John on Google