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.
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.
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.
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.
This coding style was criticized abroad decades ago and was called "Arrow-code".
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 = null
if(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.
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
- Popular Resources
- Popular amplifiers
- Red Hat announces definitive agreement to acquire Neural Magic
- 5G network speed is faster than 4G, but the perception is poor! Wu Hequan: 6G standard formulation should focus on user needs
- SEMI report: Global silicon wafer shipments increased by 6% in the third quarter of 2024
- OpenAI calls for a "North American Artificial Intelligence Alliance" to compete with China
- OpenAI is rumored to be launching a new intelligent body that can automatically perform tasks for users
- Arm: Focusing on efficient computing platforms, we work together to build a sustainable future
- AMD to cut 4% of its workforce to gain a stronger position in artificial intelligence chips
- NEC receives new supercomputer orders: Intel CPU + AMD accelerator + Nvidia switch
- RW61X: Wi-Fi 6 tri-band device in a secure i.MX RT MCU
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- CGD and Qorvo to jointly revolutionize motor control solutions
- CGD and Qorvo to jointly revolutionize motor control solutions
- Keysight Technologies FieldFox handheld analyzer with VDI spread spectrum module to achieve millimeter wave analysis function
- Infineon's PASCO2V15 XENSIV PAS CO2 5V Sensor Now Available at Mouser for Accurate CO2 Level Measurement
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- A new chapter in Great Wall Motors R&D: solid-state battery technology leads the future
- Naxin Micro provides full-scenario GaN driver IC solutions
- Interpreting Huawei’s new solid-state battery patent, will it challenge CATL in 2030?
- Are pure electric/plug-in hybrid vehicles going crazy? A Chinese company has launched the world's first -40℃ dischargeable hybrid battery that is not afraid of cold
- TMS320C6000 chip structure diagram and basic characteristics
- TI releases the latest industrial electronics reference design!
- MSP430FR6972 serial port baud rate setting code
- 【XMC4800 Relax EtherCAT Kit Review】+ FreeRTOS real-time system usage
- 【Silicon Labs BG22-EK4108A Bluetooth Development Evaluation】+ Development Environment Construction
- Do you know how to save power in RTOS applications?
- The problem of lower yield strength
- What you should know about the switching characteristics of Mosfet
- Understanding wireless communication technology
- Solving the Challenges of High-Speed Serial Connectivity