If you write if-else again, you will be wiped out

Publisher:EEWorld资讯Latest update time:2023-12-28 Source: EEWORLDKeywords:if-else Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Looking at most programming tutorials on the market, the earliest conditional statements you can come across are basically if-else.

 

As an essential function in high-level programming languages, if-else is almost a must-have in the embedded programming process. But everything has its limit. Abusing it will only make the code gradually abstract and outrageous, and eventually become a "hill of shit".

 

The programmer who took over the project complained endlessly; the CTO, who couldn't bear it, finally made up his mind to face the if-else on the screen. Whoever is caught writing if-else next time will be fined 1,000 yuan.

 

So, why is if-else so unpopular, and how to get rid of it without abusing it?


Fu Bin|Author

Electronic Engineering World (ID: EEWorldbbs)|Produced by


 The two sins of if-else 

 

In fact, we are not eliminating if-else, but recommend using it sparingly.

 

There are two reasons for this: one is that it affects the running efficiency of the program; the other is that it affects the readability of the code and increases the difficulty of operation and maintenance.

 

At present, most people's view is that if-else branch prediction (Branch Prediction) will reduce execution efficiency.

 

The execution of an instruction by the CPU is divided into four stages: IF, ID, EX, and WB. Staged execution (that is, pipeline execution) will first give a prediction result, allowing the pipeline to execute directly. If the execution is correct, it will continue; if the execution is wrong, it will go back and re-execute until it is correct.

 

picture

 

For example, in code like this:

 

int a = 0;
a += 1;
a += 2;
a += 3;

 

The CPU does not execute a +=1 after running a=0, but immediately runs the read execution of a+=1 after running a=0 read execution.

 

picture

 

Pipeline execution has many benefits, but for if statements, branch prediction will be turned on. If the prediction fails, the execution time will be affected. However, if the array is not sorted, branch prediction will most likely fail, causing the next instruction to be re-read after the instruction is executed, and the pipeline effect cannot be exerted. To put it bluntly, only when branch prediction is always successful can the CPU execution efficiency be greatly improved.

 

picture

 

However, it should be emphasized that this will happen to all statements with jump structures such as if, switch, and for. Moreover, the performance of modern CPUs far exceeds that of the past. Only a huge amount of if-else situations will affect performance. Even if performance problems occur, you have to analyze whether the performance can be better positioned on a structurally clean architecture. If this is not possible, it is okay. Replace this paragraph with assembly.

 

Therefore, in comparison, the decrease in program running efficiency is not the biggest original sin of if-else, but the impact on readability.

 

The essence of the code is for people to read. People must be able to understand it. If you scan it from top to bottom, you can roughly understand the design intention and ideas. This is good code. There is basically no if-else in such code. If you still need to read it from the top again, Next, look from the bottom to the top. Even if you understand this code this time, you will forget it after a while. That is, "high cohesion, low coupling".

 

When many engineers take over old projects, they are often faced with the fact that the code may be filled with a large number of if/else, nested 6 or 7 levels, a function has hundreds of lines, and multiple layers of judgment make it difficult to start. , despair, anger, and helplessness burst out, and such a tragedy has happened more than once. To sum it up in one sentence, look at the dead.

 

picture

 

This coding style was criticized abroad decades ago and was called "Arrow-code".

 

picture

 

In actual work, we can see situations where a method contains 10, 20 or even more logical branches. The more fatal situation is the multi-level nesting of if-else.


Multiple levels of nested code have great hidden dangers and add a lot of unnecessary complexity to the code base.

 

The human brain can only handle a few different things at one time, so when faced with the need to analyze multiple levels of code in depth, it is easy to forget the key logic of the previous level, leading to unnecessary errors.

 

Again, the code is for people to see. Our business process is already complex enough, and multiple levels of nesting will further increase its complexity.

 

if (someConditionIsMet) {
   // ...
   // ...
   // ...
   // Next are 100 lines of code
   // ...
   // ...
   // ...
   // and 100 lines of
   if (someOtherConditionIsMet) {
       // ...
       // ...
       // ...
       // Next are 100 lines of code
       // ...
       // ...
       // ...
       if (yetAnotherConditionIsMet) {
           // . ..
           // ...
           // ...
           // Next are 100 lines of code
           // ...
           // ...
           // ...
           } else {
           // Now, handle edge cases
           }
       // .. .
       // ...
       // ...
   } else {
       // Now, handle edge cases
       return someOtherResult;
   }
   // ...
   // ...
   // ...
} else {
// Now, handle edge cases
}
return someResult; 


What should you do if you encounter this situation? Don't panic, just kill the if-else.

 

 How to get rid of if-else 

The first method: exclusion strategy


Before optimization


 if (user && password) {
       // Logic processing
   } else {
       throw('Username and password cannot be empty!')
   }


Optimized


if (!user || !password) return throw('Username and password cannot be empty!')
// Logic processing


Second method: ternary operator


Compared with if-else, the ternary operator requires only one line of statements and the code is concise and concise.

 

Example 1


let allow = nullif(age >= 18){   allow = '通过'; } else {   allow = '拒绝'; }
// 优化后let allow = age >= 18 ? '通过' : '拒绝'


Example 2

if (flag) {
 success();
} else {
 fail();
}
  
//Optimized
flag ? success() : fail();


The third method: use switch, key-value and Map

if (this.type === 'A') {
 this.handleA();
} else if (this.type === 'B') {
 this.handleB();
} else if (this.type === 'C') {
 this.handleC();
} else if (this.type === 'D') {
 this.handleD();
} else {
 this.handleE();
}

 

Switch is obviously simpler, and there is no nesting between different conditional branches, and they are independent of each other, and the logic is very clear. However, the code itself can be a bit much.


switch(val){
   case 'A':
     handleA()
     break
   case 'B':
     handleB()
     break
   case 'C':
     handleC()
     break
   case 'D':
     handleD()
     break
 }

 

At this time key-value and Map are good methods.

let enums = {
 'A': handleA,
 'B': handleB,
 'C': handleC,
 'D': handleD,
 'E': handleE
}
function action(val){
 let handleType = enums[val]
 handleType()
}


let enums = new Map([
  ['A', handleA],
  ['B', handleB],
  ['C', handleC],
  ['D', handleD],
  ['E', handleE]
])
function action(val){
  let handleType = enums(val)
  handleType()
}


The fourth method: logical AND operator

 

Sometimes we can use the logical AND operator to simplify the code.

 

if( falg ){    someMethod()}
修改成:falg && someMethod();


Fifth method: Use includes to handle multiple conditions


if( code === '202' || code === '203' || code === '204' ){    someMethod()}

修改成if( ['202','203','204'].includes(code) ){    someMethod()}


The sixth method: chain of responsibility model and strategy model

 

The chain of responsibility pattern implements step-by-step processing similar to an "assembly line" structure. It is usually a chain structure that connects different implementations of "abstract processors" in series. The purpose of the strategy pattern is to decouple the use and definition of algorithms and enable routing to different strategy classes for processing based on rules.

 

Of course, it does not mean that using if-else is low, and using design patterns is high-end. The two are good at different scenarios. if-else is enough to meet the development of most daily needs, and is simple, flexible, and reliable, while design patterns are In order to be more concise, have good scalability, better performance, better readability, etc.


 Abandon the else and you will open up a new world 


Of course, no matter which reconstruction method is used, it is just an optimization. To sum it up, the simplest way is to abandon else wherever you write code. Abandoning else can reduce the number of nesting levels and effectively reduce code complexity. Make the code simpler, the structure clearer, and easier to maintain.

 

What if we ditch the else in the if-else block and prioritize this piece of logic. Handle small edge cases first and return early if necessary; otherwise, keep the main flow at the outermost level of the function.

 

if (!someConditionIsMet) {  // 首先处理那个边缘情况  return someResultOrNothing;}

// 主流程可以继续,不需要额外的保护块// ...// ...// ...// 再加 100 行代码// ...// ...// ...// 还有 100 行

return someResult;


The same idea can be applied to handle multiple edge cases:


if (!someConditionIsMet) {  // 首先处理那个边缘情况  return someResultOrNothing;}

if (!someOtherConditionIsMet) {  // 首先处理那个边缘情况  return someResultOrNothing;}

if (!yetAnotherConditionIsMet) {  // 首先处理那个边缘情况  return someResultOrNothing;}

// 主流程可以继续,不需要额外的保护块// ...// ...// ...// 再加 100 行代码// ...// ...// ...// 还有 100 行

return someResult;

 

Because edge cases are handled at the top of the function, developers are less likely to overlook them when adding new code later, reducing the risk of introducing bugs. Handling edge cases and returning early can reduce unnecessary calculations, potentially making your code more efficient.

 

Simplified code structure is easier to understand by colleagues, making the code review process smoother and reducing the spread of potential errors and bad practices.

 

Of course, some engineers believe that we should not pay too much attention to the number and layers of if-else, but focus on whether the semantics are clear. Simply reducing if-else but making the code more difficult to read is superfluous. There is no benefit in arbitrarily optimizing if-else. What should be optimized is the segmentation of its own conditions. After the flow is clarified, if-else will be clearer than anything else.

[1] [2]
Keywords:if-else Reference address:If you write if-else again, you will be wiped out

Previous article:Lingang New Area Fund Company and industry leader Reside Technology held the 2023RT-Thread Developer Conference
Next article:How the shift in embedded development will impact the future of computing

Latest Embedded Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号