Nested Conditionals
Basic Example
#include <stdio.h>
int main(void) {
int age = 25;
int hasLicense = 1;
if (age >= 18) {
if (hasLicense) {
printf("You may drive.\n");
} else {
printf("You need a license first.\n");
}
} else {
printf("You are too young to drive.\n");
}
return 0;
}Readability Concerns With Deep Nesting
// Deep nesting is hard to follow: four levels of indentation
// before we even reach the real work.
if (user != NULL) {
if (user->isActive) {
if (user->hasPermission) {
if (resource != NULL) {
processRequest(user, resource);
}
}
}
}else at the correct level, or misjudge which condition actually guards a given line. Treat more than two or three levels of nesting as a signal to refactor.Flattening With Guard Clauses
return, continue, orbreak) instead of wrapping the rest of the function in another level of if. Each guard clause removes one level of nesting, so the "main" logic of the function ends up flat and easy to read./* BEFORE: nested conditionals, four levels deep */
void processRequestNested(User *user, Resource *resource) {
if (user != NULL) {
if (user->isActive) {
if (user->hasPermission) {
if (resource != NULL) {
doWork(user, resource);
}
}
}
}
}
/* AFTER: guard clauses flatten the same logic to a single level */
void processRequestFlat(User *user, Resource *resource) {
if (user == NULL) return;
if (!user->isActive) return;
if (!user->hasPermission) return;
if (resource == NULL) return;
doWork(user, resource);
}When Nesting Is Still the Right Choice
Not all nesting is bad. When a decision genuinely branches into several distinct outcomes at each level (rather than repeatedly bailing out on invalid input), a shallow nest of two levels is often the clearest way to express it. The goal is not to eliminate nesting entirely, but to avoid nesting so deep that the logic becomes hard to trace.
if as an early return/continue/break without changing behavior, do it. If the branches genuinely represent different outcomes that all need to keep executing in context, a small amount of nesting is fine.Key Points
Nested conditionals let you express dependent checks, but each level adds cognitive overhead for the reader.
Deep nesting (the "pyramid of doom") makes it easy to misplace statements or lose track of which condition guards them.
Guard clauses -- early returns/continues/breaks for invalid or uninteresting cases -- flatten nested conditionals into a linear sequence.
Aim to keep nesting to two or three levels at most; beyond that, look for a guard-clause refactor.