Ever found yourself writing long chains of if-else statements just to decide what value to return? It works, but it makes your code bulky, repetitive, and harder to scan. When you need to map multiple conditions to specific results in a cleaner, more predictable way, there’s a better approach through Dart switch expression.
Switch expressions let you evaluate conditions and directly return a value based on the result, all within a compact expression. They make your conditional logic more readable and consistent, especially in cases where you’re matching known values or working with enums.
Traditional Switch vs Modern Switch Expression
Before Dart introduced switch expressions, developers relied on the traditional switch statement to handle multiple condition checks. It worked, but it often required more lines of code, repeated break statements, and couldn’t directly return a value.
Here’s a quick example of a traditional switch statement:
String evaluateScore(int score) {
switch (score) {
case 10:
return 'Perfect score!';
case 8:
return 'Great effort!';
case 5:
return 'Average performance.';
default:
return 'Needs improvement.';
}
}
void main() {
print(evaluateScore(8));
}
Now, the same logic can be rewritten with a switch expression, which allows you to return a value directly and write more compact code:
void main() {
final score = 8;
final result = switch (score) {
10 => 'Perfect score!',
8 => 'Great effort!',
5 => 'Average performance.',
_ => 'Needs improvement.'
};
print(result);
}
Both codes achieve the same goal, but the switch expression is shorter, eliminates the need for break, and evaluates to a value directly. This makes it cleaner, easier to maintain, and ideal for quick condition-to-value mapping.
Writing Switch Expressions in Dart
A switch expression lets you evaluate a value and return a result based on matching patterns. It follows a simple structure: each case uses an arrow => to map a condition to a result, and all possible cases must be handled to keep it exhaustive. The underscore _ acts as a catch-all, similar to default in the old switch.
Here’s a basic example:
void main() {
final fruit = 'Orange';
final message = switch (fruit) {
'Apple' => 'Keeps you healthy.',
'Banana' => 'Gives you instant energy.',
'Orange' => 'Rich in Vitamin C.',
_ => 'Unknown fruit.'
};
print(message);
}
Each arm evaluates to a single expression, and the overall result can be stored in a variable or returned directly.
You can also use enums to make the code even more structured:
enum Weather { sunny, rainy, cloudy }
String weatherAdvice(Weather w) => switch (w) {
Weather.sunny => 'Perfect for a walk.',
Weather.rainy => 'Carry an umbrella.',
Weather.cloudy => 'Might rain later.',
};
void main() {
print(weatherAdvice(Weather.cloudy));
}
Errors and Edge Behaviors in Switch Expressions
While switch expressions are designed to simplify conditional logic, a few details can trip you up if you’re not careful.
1. Missing exhaustive cases: Every switch expression must handle all possible inputs. If Dart detects a missing case, it throws a compile-time error.
enum Light { red, yellow, green }
String action(Light l) => switch (l) {
Light.red => 'Stop',
Light.green => 'Go',
// Missing Light.yellow — causes compile-time error
};
To fix it, you can either add the missing case or use _ as a fallback:
String action(Light l) => switch (l) {
Light.red => 'Stop',
Light.green => 'Go',
_ => 'Proceed with caution'
};
2. Multi-statement bodies are not allowed: Each arm must be a single expression. If you need multiple steps, call a function or compute inside braces before returning a value.
// Invalid
final result = switch (5) {
5 => { print('Five'); 'Value 5'; } // multiple statements not allowed
_ => 'Other number'
};
Here’s the fix:
final result = switch (5) {
5 => logAndReturn(),
_ => 'Other number',
};
String logAndReturn() {
print('Five');
return 'Value 5';
}
3. Type consistency: All arms must return values of the same type. Mixing types causes type inference errors.
// Invalid - returns both String and int
final result = switch (true) {
true => 'Yes',
false => 0
};
Here’s the fix:
final result = switch (true) {
true => 'Yes',
false => 'No',
};
4. Expression-only usage: Switch expressions must evaluate to a value. They can’t stand alone as statements without an assignment or return.
switch (5) {
5 => 'Five',
_ => 'Other',
}; // Doesn't do anything
Here’s the fix:
final result = switch (5) {
5 => 'Five',
_ => 'Other',
};
print(result);
Being mindful of these behaviors ensures your switch expressions stay predictable and compile safely.
Wrapping Up
Switch expressions make Dart code cleaner and more expressive by turning long conditional chains into single-line value mappings. They’re especially useful when working with enums, pattern matching, or returning results directly without extra variables or break statements.
As a best practice, keep each case simple, ensure all possible patterns are covered, and use _ only as a fallback when no other condition applies. Avoid complex logic inside arms and maintain consistent return types across all cases. Writing clear, exhaustive switch expressions will make your Dart code easier to reason about and maintain.