skip to content

In Dart, what does the => arrow syntax mean in a function or member declaration, and what can't you write after it?

level: juniorimportance: should knowfreq 42%

answer

  1. shorthand for a single return
  2. expressions only, no statements
  3. conditional and switch expressions qualify
  4. braces after the arrow
  5. fine on void functions and setters

basics

~20 s

In Dart, => expr; is shorthand for { return expr; }. Only an expression may follow the arrow: a conditional or switch expression works, an if statement or loop does not, and => { ... } is a collection literal, not a block.

solid answer

~40 s

`=> expr;` is exactly `{ return expr; }`, and it works for functions, methods, getters, setters, operators and anonymous functions, such as `void main() => runApp(const App());`. Only an expression may follow the arrow: `cond ? a : b`, a switch expression or a `throw` are fine, while an `if` statement or a loop is not. A common Flutter slip is `onTap: () => { save() }`; the braces are parsed as a set or map literal, not a block, so write `() => save()` or `() { save(); }`. On a `void` function the expression's value is simply discarded. Effective Dart suggests arrows for simple members and a block body once the expression gets long or nested.

code

dart · 22 lines
dart
class Price {
  Price(this.amount);
  num amount;

  bool get isFree => amount == 0; // getter
  String get label => isFree ? 'Free' : '$amount EUR'; // conditional expression
  set discount(num percent) => amount = amount * (100 - percent) / 100; // setter
}

String tier(num amount) => switch (amount) {
  0 => 'free',
  < 10 => 'cheap',
  _ => 'regular',
};

void log(String message) => print(message); // value discarded

void main() {
  final p = Price(20)..discount = 50;
  log(p.label); // 10.0 EUR
  log(tier(p.amount)); // regular
}

go deeper

for a junior

Recall that => expr; means { return expr; } and that only an expression may follow the arrow.

for a middle

Explain which constructs count as expressions (conditional, switch expression, throw) and why => { } creates a collection literal.

for a senior

Review for readability: spot arrow bodies that hide cascades or nested conditionals and ask for a block body with named locals.

for a principal

Decide whether to adopt prefer_expression_function_bodies across the codebase, weighing brevity against readability of complex members.

## What `=>` means In a Dart function or member declaration, `=> expr;` is shorthand for a block body that returns that expression: `{ return expr; }`. It is often called **arrow syntax**. ```dart bool isFree(num price) => price == 0; // same as bool isFree(num price) { return price == 0; } ``` It works on top-level functions, methods, getters, setters, operators and function expressions (anonymous functions). A classic Flutter example is `void main() => runApp(const App());`. ## Only an expression may follow The part between `=>` and `;` must be an **expression**, something that evaluates to a value. Statements are not allowed: | After `=>` | Allowed? | |---|---| | `a > b ? a : b` (conditional expression) | yes | | `switch (x) { ... }` as a switch **expression** | yes | | `throw StateError('nope')` (throw is an expression) | yes | | `if (a > b) a` (if statement) | no | | `for (...) ...` (loop) | no | | `{ a; b; }` (a block) | no: the braces become a set or map literal | The last row is a real trap. Code written as `onTap: () => { save() }` does **not** run a block containing `save()`. The braces after `=>` are parsed as a **set or map literal**, so at best the function returns a collection built from that expression, and depending on the types the analyzer may reject it. Write `onTap: () => save()` or use a block body `onTap: () { save(); }`. ## Arrow on `void` functions An arrow body is fine on a `void` function: `void log(String m) => print(m);`. The expression is evaluated and its value is discarded because the declared return type is `void`. Setters work the same way: `set width(num v) => _width = v;`. ## When to use it, according to Effective Dart Effective Dart says to **consider `=>` for simple members** that compute and return a value, and warns against abusing it: - Good fits: getters like `double get area => width * height;`, one-line helpers, small setters paired with arrow getters. - Poor fits: anything longer than a couple of lines or with deeply nested expressions; cascades and chained conditionals are named as common offenders. Switch to a block body with statements and local variables. The `prefer_expression_function_bodies` lint (not in the default sets) suggests arrows where a block holds a single `return`. ## Summary of the mechanics 1. `=> e;` equals `{ return e; }`. 2. Only expressions may follow; conditional expressions, switch expressions and `throw` qualify, statements do not. 3. `=> { ... }` is a collection literal, not a block. 4. On a `void` function the value is discarded. 5. Prefer a block body once readability suffers. ## Arrow bodies in anonymous functions Arrow syntax is most common in **function expressions** passed as arguments: `prices.where((p) => p > 0)`, `items.map((i) => i.name)`. The same rule applies: one expression, implicitly returned. When a callback needs two statements, such as updating state and logging, use a block body `(p) { ... }` rather than squeezing both into one expression with a cascade or a comma-separated trick. Closures and tear-offs, and how they capture variables, are a separate topic. ## What an interviewer listens for - The exact equivalence with `{ return expr; }`. - The expression-only rule, with an example of a statement that fails. - The `=> { }` trap, which is common in Flutter callbacks. - Judgement about when an arrow stops helping readability.

  • What does the Flutter callback onPressed: () => { save() } actually do?
    The braces after `=>` are parsed as a collection literal, not a block. Where it compiles at all, the closure evaluates `save()` as the element of a set literal and returns that set, instead of running a block of statements; depending on types the analyzer may reject it. Either way it signals a misunderstanding. Write `onPressed: () => save()`, a block body `() { save(); }`, or `onPressed: save` if the signature matches.
  • Can you use => with an if/else in Dart?
    Not with an `if` statement, because only expressions may follow the arrow. Use a conditional expression, `=> isFree ? 'Free' : '$amount EUR';`, or, for several branches, a Dart 3 switch expression. When the logic needs statements or local variables, switch to a block body.

saying these in an interview costs you the question

  • Thinks => can only be used on anonymous functions
  • Puts an if statement after =>
  • Writes () => { doWork() } expecting a block
  • Believes arrow functions cannot return void
  • Uses => for long nested expressions to save lines