Skip to main content

By protecting others, we save ourselves.
If you only think of yourself, you'll only destroy yourself.

七人の侍
Why I don't use Else

Many years back I stopped using the else clause. At first glance this self imposed limitation might sound a bit pedantic. However I believe that by not using the else clause one can avoid many of the pitfalls one encounters when searching for the right decomposition of a problem domain.

In this article I will try to explain why I stopped using the else clause. Please do not think this is me telling you what to do. My goal is not to force a dogmatic approach to software development. Rather I hope to introduce you an approch that works really well for me and inspire you to give it a try.

The easiest justification for not using the else clause is the fact that the else clause adds nothing of value to the code. Removing an else clause never reduces the capabilities of a function.

// Simple function with else

function simpleFunction(String $input): bool {
	if ($input === 'some value') {
		return true;
	} else {
		return false;
	}
}
// Simple function without else

function simpleFunctionWithoutElse(String $input): bool {
	if ($input === 'some value') {
		return true;
	}

	return false;
}
Looking at the two examples above we can see that they return the same values under the same conditions. So we can assert that they are functionally equivilent and that in this example the else clause adds no value.

Every line of code I write must provide something of value. It must justify it's existence because every line of code in a system has a cost associated with it. Every line uses more system memory, more cognitive energy to understand, more effort to maintain.

This principle helps to prevent incidental complexity. It also reduces technical debt, because if some code can be removed without a negative impact on the efficiency, clarity or functionality of the application, then it should be removed.

Of course this doesn't mean that fewer lines of code is always better. Clarity is probably the most valuable characteristic of software, thus code that improves clarity justifies its existence.

The else clause however does not improve clarity and often times it reduces clarity by making the developer maintain 3 contextual states in their mind when in reality there are only two true states in the method.

// Faux state example

function ExampleFunction(String $input): string {

    // INITIAL FIRST STATE

	if ($input === 'some value') {
		$someVar = 'Something '; 
       // SECOND STATE
	} else {
		$someVar = 'Something else'; 
       // THIRD STATE
	}

	// Do some work here

	return $result;
}
// No Faux state
function ExampleFunction(String $input): string {

    // INITIAL FIRST STATE
	$someVar = 'Something else';

	if ($input === 'some value') {
		$someVar = 'Something '; 
       // SECOND STATE
	} 

	// Do some work here

	return $result;
}

Again these two method are functionally equal. However from a cognitive standpoint we don't have to deal with 3 contexts. There is the intial state and the alternative or conditional state.

The only use of the else clause that doesn’t violate some part of the clean coding principles is simple conditional assignment. However in PHP and many other languages this can be accomplished with more clarity using a ternary operator.

Reusing the example from above we can see this in action.

// Faux state example

function ExampleFunction(String $input): string {

	if ($input === 'some value') {
		$someVar = 'Something '; 
	} else {
		$someVar = 'Something else'; 
	}

	// Do some work here

	return $result;
}

function ExampleFunction(String $input): string {

	$isSomeValue = ($input === 'some value');

	$someVar = $isSomeValue 
	? 'Something '
	: 'Something else';

	// Do some work here

	return $result;
}

In Robert Martin’s book, “Clean Code: A Handbook of Agile Craftsmanship”, he stresses time and time again the need to keep functions small and that indentation should be no more than one or two levels deep.

Because nested control strucutres are generally a sign of a method doing too much and because nested strucutres increase the amount of cognitive energy needed to comprehend and track what is going on.

Using else clauses increases the indentation level of a method with no benefit. Removing else clauses reduces nested structures. Which reduces the amount of cognitive energy needed to comprehend it.
He also suggests that the content of most control structures should consist of no more than a line or two because anything longer than that suggests that the content of that clause should be in an independent function.

While I agree with him regarding general control structures, I don't think if/else statements should be treated the same. Because doing so would lead to framentation of logic.

Since the content of the else clause is essentially the default state of the current function, extracting it into a seperate function hides the relationship between the conditions and the results.

Instead I extract the conditional as a whole and move that into its own method. Which improves clarity in the main method and reduces the size of complexity in the newly created function.

// Example class using Robert Martin’s recommended approch. 

class Foo {
     private string $property;
     private ResultType $result;
     
     public function getCalculatedResult(): ResultType {
         // do some checks and return 
         if ($this->something()) { 
            // specific and narrow exceptional case
            $this->calculateSomething();
         } else { // default case
            $this->calculateSomethingElse();
          }

         $this->additionalComputation();
         return $this->result;
     }

     private function something(): bool {
         // do some checks and return 
     }

     private function calculateSomething(): void {
         // do some calculations 
     }

     private function calculateSomethingElse(): void {
         // do some calculations 
     }

     private function additionalComputation(): void {
         // do some calculations 
     }
}
In the above class we have done what was recommended by moving the contents of the conditional to separate methods with descriptive names. However the Foo::getCalcualtedResult method is still very convoluted.
So instead I like to move the entire conditonal further down the execution path. This makes the intent of Foo::getCalculatedResult clearer and brings the conditional closer to where it actually matters.
// Example of moving the entire conditional together.

class Foo {
     private string $property;
     private ResultType $result;
     
     public function getCalculatedResult(): ResultType {

         $this->calculateSomething();
         $this->additionalComputation();
         return $this->result;
     }

     private function something(): bool {
         // do some checks and return 
     }

     private function calculateSomething(): void {
         // do some checks and return 
         if ($this->something()) { 
            // specific and narrow exceptional case
            // do some calculations 
         } else { // default case
            $this->calculateSomethingElse();
          }
     }

     private function calculateSomethingElse(): void {
         // do some calculations 
     }

     private function additionalComputation(): void {
         // do some calculations 
     }
}
This approach has the added benefit of preventing you from accidentally bypass the edge case consideration 6 months from now when you've forgotten the details.
You might have notice we haven't removed the else clause yet. But since we already know that the else clause adds no value, we can easily remove it while keeping behavior parity. We accomplish this by using an early return.

     private function calculateSomething(): void {
         // do some checks and return 
         if ($this->something()) { 
            // specific and narrow exceptional case
            // do some calculations 
			return;
         } 
		
		// delegate the default case
        $this->calculateSomethingElse();
     }

As you can see, not using the else clause helps us to decompose our problem domain in such a way that it naturally conforms to the single responsibility principle, gives meaningful names to conditional logic, and hides conditionality from the main execution path.

On the micro level the positive impact might seem marginal at best, but on the macro level the impact can be profound. Removing the else clause will have a positive impact on efficiency, clarity, functionality and pretty much every other metric of software quality.

However you don’t have to take my word for it. Try it for yourself. Challenge yourself to 30 days of not using and removing else clauses wherever you find them in your work. 

You have nothing to lose and can always go back to using the else clause at anytime. However I’m confident that once you get the hang of it, you’ll never want to go back.

Thanks for reading and happy coding

Credit where credit is due.

I just wanted to take a moment to thank everyone on r/webdev for their brutally honest feedback on the topic and the article. The examples used in this article were inspired by our discussion and I think it helped me add a little more depth to the idea.