On this page25 sections
- Prerequisites
- Connection With Previous Lectures
- Learning Objectives
- 1. The Arrow Shortcut
- 2. Reading an Arrow Function
- 3. Arrow Functions That Return Nothing
- 4. Only One Expression
- 5. Choices Inside an Arrow
- 6. Functions Without a Name
- 7. Storing a Function in a Variable
- 8. Anonymous Arrow Functions
- 9. Dart Still Checks Every Call
- 10. Swapping the Function
- 11. What dart analyze Says
- 12. Passing a Function Directly
- 13. A Real-World Example
- Code Examples
- Common Beginner Mistakes
- Best Practices
- Mini Challenge
- Practice Questions
- Practice Answers
- Quick Revision
- Key Takeaways
- What's Next?
Lecture 34 — Arrow & Anonymous Functions
| Category | 6 — Functions |
| Lecture | 034 of 140 |
| Estimated video length | 16 min |
| Target | Dart 3.12.2 |
| Level | Beginner |
Three lines of braces and
returnjust to give backn * nis a lot of ceremony. Arrow functions shrink a one-expression function to one line, and anonymous functions let you create a function without even giving it a name.
Contents
Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways
Every error message in this lecture is real. Each one was produced by running the code shown on Dart 3.12.2, so you will recognize it when you meet it yourself.
Prerequisites
Students should already understand, from Lectures 001–033:
- conditional expressions
? :(Lecture 020) and switch expressions with=>arms (Lecture 025) for-inloops over a group of values in square brackets, like[85, 92, 78](Lecture 027)- defining and calling functions with typed parameters and a return type (Lectures 030–031)
return, and why every path of a non-voidfunction must return a value
Connection With Previous Lectures
Lecture 031 ended with many small functions like these:
int square(int n) {
return n * n;
}
bool isAdult(int age) {
return age >= 18;
}Each one does a single calculation, yet takes three lines: braces, the word return, and a
semicolon around one small expression. A program with twenty such helpers is mostly braces.
And every function so far needed a name, even one we planned to use exactly once. This
lecture removes both kinds of ceremony.
Learning Objectives
By the end of this lecture you will be able to:
- Write a function body with the arrow
=>instead of braces andreturn - Explain why an arrow body must be a single expression
- Use
? :and switch expressions to make choices inside an arrow body - Create an anonymous function and store it in a variable
- Call a function stored in a variable, and recognize the checks Dart still applies
- Replace the function inside a variable with another of the same type
- Pass an anonymous function directly to
forEach - Choose between braces, an arrow, and an anonymous function
1. The Arrow Shortcut
When a function's body is just return plus one expression, you can write => and the
expression instead.
int square(int n) => n * n;
void main() {
print(square(4));
}16=> n * n; means exactly the same as { return n * n; }. The function still has a name, a
parameter, and a return type — only the body is shorter. This is called an arrow function.
Analogy — the arrow is like a sign pointing to the answer: "
square(n)→ go ton * n". You met the same sign in Lecture 025, where a switch arm1 => 'Monday'pointed to its result.
2. Reading an Arrow Function
| Long form | Arrow form |
|---|---|
int square(int n) { return n * n; } | int square(int n) => n * n; |
bool isAdult(int age) { return age >= 18; } | bool isAdult(int age) => age >= 18; |
Three things change: the braces go, the word return goes, and => takes their place. The
semicolon stays — it now ends the whole function.
bool isAdult(int age) => age >= 18;
String fullName(String first, String last) => '$first $last';
double average(int total, int count) => total / count;
void main() {
print(isAdult(20));
print(fullName('Sara', 'Khan'));
print(average(240, 3));
}true
Sara Khan
80.03. Arrow Functions That Return Nothing
A void function can use an arrow too, when its whole job is one call:
void greet(String name) => print('Hello, $name!');
void main() {
greet('Ali');
greet('Zayan');
}Hello, Ali!
Hello, Zayan!Nothing is given back; => here simply means "the body is this one expression".
4. Only One Expression
An arrow body must be a single expression — something that produces a value. Statements
such as return or if are not allowed after =>:
int square(int n) => return n * n; // ✗
void main() {
print(square(3));
}Error: Unexpected token 'return'.
int square(int n) => return n * n; // ✗
^^^^^^The arrow already means "return", so the word is not needed. An if fails too, with several
errors starting with Expected an identifier, but got 'if'.
5. Choices Inside an Arrow
You can still make a choice — with the expression forms of choosing. Use ? : for two
options (Lecture 020) and a switch expression for more (Lecture 025):
String result(int marks) => marks >= 50 ? 'Pass' : 'Fail';
String grade(int marks) => switch (marks) {
>= 80 => 'A',
>= 60 => 'B',
_ => 'C',
};
void main() {
print(result(72));
print(grade(85));
print(grade(40));
}Pass
A
CIf a function needs several statements — a variable, a loop, an early return — keep the braces. The arrow is for functions that are one expression naturally.
6. Functions Without a Name
Every function so far had a name. An anonymous function leaves the name out: just the parameters and a body.
(int a, int b) {
return a + b;
}On its own this does nothing — like writing a number on a line without storing it. To use an anonymous function, you either store it in a variable or hand it straight to something that will call it. Anonymous functions are also called lambdas in many languages.
7. Storing a Function in a Variable
Put the anonymous function on the right side of =. Note the semicolon after the closing
brace — the whole thing is one variable declaration.
void main() {
var add = (int a, int b) {
return a + b;
};
print(add(2, 3));
print(add(10, 20));
}5
30You call the variable with parentheses, exactly like a named function. add holds a
function, and add(2, 3) runs it.
8. Anonymous Arrow Functions
An anonymous function can use an arrow body too. A function with no parameters keeps empty parentheses:
void main() {
var square = (int n) => n * n;
var sayHi = () => print('Hi!');
print(square(5));
sayHi();
}25
Hi!(int n) => n * n reads: "a function that takes an int called n and gives back
n * n".
9. Dart Still Checks Every Call
A function in a variable is just as strict as a named one. The types of its parameters and its result are inferred from the anonymous function:
void main() {
var square = (int n) => n * n;
print(square.runtimeType);
print(square('3')); // ✗
}Error: The argument type 'String' can't be assigned to the parameter type 'int'.
print(square('3')); // ✗
^Remove the broken line and the program prints (int) => int: a function that takes an
int and returns an int. Function types like this — and writing them yourself — are the
topic of Lecture 035.
10. Swapping the Function
Why store a function in a variable instead of naming it? Because a variable can change. You can put a different function into it, as long as the types match:
void main() {
var greet = (String name) => 'Hello, $name!';
print(greet('Ali'));
greet = (String name) => 'Salaam, $name!';
print(greet('Ali'));
}Hello, Ali!
Salaam, Ali!The same call, greet('Ali'), now runs a different function. A function with different
types does not fit:
void main() {
var greet = (String name) => 'Hello, $name!';
greet = (int n) => 'Number $n'; // ✗
print(greet('Ali'));
}Error: A value of type 'String Function(int)' can't be assigned to a variable of type 'String Function(String)'.
greet = (int n) => 'Number $n'; // ✗
^11. What dart analyze Says
If a variable gets one function and never changes, dart analyze suggests a normal
declaration instead. For var square = (int n) => n * n; it prints:
info - Use a function declaration rather than a variable assignment to bind a function to a name. Try rewriting the closure assignment as a function declaration. - prefer_function_declarations_over_variablesThis is style advice, not an error — the program runs. The fix is the arrow function from
Step 1: int square(int n) => n * n;. Store a function in a variable when it really varies,
as in Step 10; Lecture 035 shows more reasons to treat functions as values.
12. Passing a Function Directly
The most common home of an anonymous function is as an argument. A group of values in
square brackets has a forEach method, which calls your function once for each value:
void main() {
['Ali', 'Sara', 'Zayan'].forEach((name) {
print('Hello, $name!');
});
}Hello, Ali!
Hello, Sara!
Hello, Zayan!The function has no name and is never stored — it is written right where it is needed.
forEach hands it 'Ali', then 'Sara', then 'Zayan'. Dart even infers that name is a
String, so the type can be left out here. With an arrow:
void main() {
[85, 92, 78].forEach((mark) => print('Mark: $mark'));
}Mark: 85
Mark: 92
Mark: 78For a job this simple, the for-in loop from Lecture 027 is clearer, and dart analyze
says so with Function literals shouldn't be passed to 'forEach'. Try using a 'for' loop.
We use forEach only as the first glimpse of passing a function. Functions that take other
functions are the topic of Lecture 036, and lists themselves begin in Lecture 039.
13. A Real-World Example
double lineTotal(double price, int quantity) => price * quantity;
String money(double amount) => 'Rs ${amount.toStringAsFixed(2)}';
void main() {
var discount = (double amount) => 0.0;
double total = lineTotal(250, 3) + lineTotal(40, 5);
print('Total: ${money(total)}');
print('Discount: ${money(discount(total))}');
// Sale day: swap in a new discount rule
discount = (double amount) => amount >= 500 ? amount * 0.10 : 0.0;
print('Sale discount: ${money(discount(total))}');
print('To pay: ${money(total - discount(total))}');
}Total: Rs 950.00
Discount: Rs 0.00
Sale discount: Rs 95.00
To pay: Rs 855.00lineTotal and money are fixed one-expression jobs, so they are arrow functions. The
discount rule changes on sale days, so it lives in a variable holding an anonymous function,
and the rest of the program calls discount(total) without caring which rule is inside.
Code Examples
Example 1 — An Arrow Function
int cube(int n) => n * n * n;
void main() {
print(cube(3));
}27Example 2 — Arrow Returning a bool
bool isEven(int n) => n % 2 == 0;
void main() {
print(isEven(10));
print(isEven(7));
}true
falseExample 3 — A void Arrow Function
void line() => print('----------');
void main() {
line();
print('Report');
line();
}----------
Report
----------Example 4 — A Choice in an Arrow
String status(bool online) => online ? 'Online' : 'Offline';
void main() {
print(status(true));
print(status(false));
}Online
OfflineExample 5 — Swapping a Stored Function
void main() {
var format = (String name) => name.toUpperCase();
print(format('Sara'));
format = (String name) => name.toLowerCase();
print(format('Sara'));
}SARA
saraExample 6 — An Anonymous Function as an Argument
void main() {
['Pen', 'Notebook', 'Bag'].forEach((item) => print('- $item'));
}- Pen
- Notebook
- BagExample 7 — Student Marks
double average(int total, int subjects) => total / subjects;
String grade(double avg) => switch (avg) {
>= 80 => 'A',
>= 60 => 'B',
_ => 'C',
};
void main() {
double avg = average(80 + 75 + 85, 3);
print('Average: $avg, Grade: ${grade(avg)}');
}Average: 80.0, Grade: AExample 8 — Shopping Total
double withTax(double price) => price * 1.05;
void main() {
double total = 0;
[200.0, 100.0, 50.0].forEach((price) {
total += withTax(price);
});
print('Total with tax: $total');
}Total with tax: 367.5How it works
forEachcalls the anonymous function once for each price.- Inside it, the arrow function
withTaxadds 5%. - The anonymous function can update
total, a variable ofmain. Why it can seetotalis explained in Lecture 037 — Closures & Scope.
Example 9 — Bank Balance
void main() {
var fee = (int amount) => 0;
int balance = 1000;
balance -= 300 + fee(300);
print('Balance: $balance');
fee = (int amount) => amount ~/ 100;
balance -= 300 + fee(300);
print('Balance: $balance');
}Balance: 700
Balance: 397How it works
- At first the fee rule returns
0, so withdrawing300costs300. - Then a new rule is stored: 1 rupee per 100 withdrawn, so the next
300costs303. - The withdrawal lines are identical — only the function in
feechanged.
Example 10 — Temperature Conversion
double toFahrenheit(double c) => c * 9 / 5 + 32;
String describe(double c) => c >= 30 ? 'hot' : 'pleasant';
void main() {
[34.0, 22.0].forEach((c) {
print('$c°C = ${toFahrenheit(c)}°F, ${describe(c)}');
});
}34.0°C = 93.2°F, hot
22.0°C = 71.6°F, pleasantCommon Beginner Mistakes
1. Writing return after the arrow
// int square(int n) => return n * n;Error: Unexpected token 'return'.The arrow already returns. Write int square(int n) => n * n;.
2. Putting braces after the arrow
// int square(int n) => {n * n};Error: A value of type 'Set<int>' can't be returned from a function with return type 'int'.After =>, braces don't make a block — they make a Set, a kind of collection (Lecture
047). Use the arrow or braces, never both. With void, => {print('Hi')}; even compiles,
and only dart analyze warns: Braces unnecessarily wrap this expression in a set literal.
3. Forgetting the semicolon after a stored function
// var add = (int a, int b) {
// return a + b;
// }Error: Expected ';' after this.The declaration ends after the closing brace, so it needs };.
4. Forgetting the parentheses when calling
void main() {
var sayHi = () => print('Hi!');
sayHi; // ✗ mentions the function, does not call it
print('end');
}endNo error and no Hi!. sayHi is the function itself; sayHi() runs it.
5. Leaving out parameter types in a stored function
void main() {
var add = (a, b) => a + b;
print(add.runtimeType);
}(dynamic, dynamic) => dynamicWith no types to go on, a and b become dynamic (Lecture 011), so add('Ali', 5)
compiles and then crashes while running. Write (int a, int b) => a + b. Inside forEach
the types are inferred, so they may be left out there.
6. Forcing several statements into an arrow
=> if ... and => return ... do not compile. Use ? : or a switch expression, or go back
to braces.
Best Practices
- Use an arrow when the body is one short expression; use braces for anything longer.
- Keep arrow functions readable on one line — if it wraps awkwardly, use braces.
- Give a fixed, reused job a name:
int square(int n) => n * n;. - Store a function in a variable only when the function itself may change.
- Always type the parameters of a stored anonymous function.
- For a simple "do this for each value", prefer a
for-inloop overforEach.
Mini Challenge
Write an arrow function int bonus(int marks) that returns 10 when marks are 90 or more and
0 otherwise. Then store an anonymous function report that takes a String name and an
int mark and prints <name>: <mark + bonus>. Call report for Ali (95) and Zayan (70).
Your program should print exactly:
Ali: 105
Zayan: 70Try it yourself before opening the solution.
Show solution
int bonus(int marks) => marks >= 90 ? 10 : 0;
void main() {
var report = (String name, int marks) =>
print('$name: ${marks + bonus(marks)}');
report('Ali', 95);
report('Zayan', 70);
}Ali: 105
Zayan: 70How it works
bonusis one expression,? :, so it is an arrow function.reportis an anonymous arrow function stored in a variable and called twice.dart analyzesuggests makingreporta declaration — try it:void report(...) => ....
Practice Questions
Work through these in order — they run from beginner to application to challenge. Every question gives you exact values, so you can compare your output with the answers.
Beginner
- Rewrite
int twice(int n) { return n * 2; }as an arrow function. Printtwice(21). - Write an arrow function
bool isPositive(int n). PrintisPositive(-4). - Write a
voidarrow functionwelcome(String name)that printsWelcome, <name>!. Call it with'Sara'.
Application
- Store an anonymous function in a variable
areathat takesint widthandint heightand returns their product. Printarea(12, 5). - Write an arrow function
String size(int n)that returns'big'whennis over 100 and'small'otherwise. Printsize(250)andsize(8). - Use
forEachwith an anonymous arrow function to printHi, <name>for'Ali','Sara'and'Zayan'. - Store
var message = (String name) => 'Good morning, $name';, print it for'Ali', then swap in a function returning'Good night, $name'and print it for'Ali'again. - Write
String day(int n)as an arrow function with a switch expression:1→'Mon',2→'Tue', anything else →'?'. Printday(2)andday(9).
Challenge
- Write an arrow function
double celsius(double f) => …that converts Fahrenheit to Celsius with(f - 32) * 5 / 9. UseforEachon[212.0, 32.0]to print<f>°F = <c>°Cfor each value. - Starting with
int balance = 500, storevar interest = (int b) => 0;. Addinterest(balance)tobalanceand print it. Then swap in a rule giving 10% with~/(b ~/ 10), add the interest again, and print the balance.
Practice Answers
Question 1 — Solution
int twice(int n) => n * 2;
void main() {
print(twice(21));
}42Question 2 — Solution
bool isPositive(int n) => n > 0;
void main() {
print(isPositive(-4));
}falseQuestion 3 — Solution
void welcome(String name) => print('Welcome, $name!');
void main() {
welcome('Sara');
}Welcome, Sara!Question 4 — Solution
void main() {
var area = (int width, int height) => width * height;
print(area(12, 5));
}60Question 5 — Solution
String size(int n) => n > 100 ? 'big' : 'small';
void main() {
print(size(250));
print(size(8));
}big
smallQuestion 6 — Solution
void main() {
['Ali', 'Sara', 'Zayan'].forEach((name) => print('Hi, $name'));
}Hi, Ali
Hi, Sara
Hi, ZayanQuestion 7 — Solution
void main() {
var message = (String name) => 'Good morning, $name';
print(message('Ali'));
message = (String name) => 'Good night, $name';
print(message('Ali'));
}Good morning, Ali
Good night, AliQuestion 8 — Solution
String day(int n) => switch (n) {
1 => 'Mon',
2 => 'Tue',
_ => '?',
};
void main() {
print(day(2));
print(day(9));
}Tue
?Question 9 — Solution
double celsius(double f) => (f - 32) * 5 / 9;
void main() {
[212.0, 32.0].forEach((f) => print('$f°F = ${celsius(f)}°C'));
}212.0°F = 100.0°C
32.0°F = 0.0°CQuestion 10 — Solution
void main() {
int balance = 500;
var interest = (int b) => 0;
balance += interest(balance);
print('Balance: $balance');
interest = (int b) => b ~/ 10;
balance += interest(balance);
print('Balance: $balance');
}Balance: 500
Balance: 550Quick Revision
- What does
=> exprreplace in a function body? - Why can't
returnorifappear after=>? - Which two expression forms let an arrow function make a choice?
- What is an anonymous function?
- Why does
var add = (int a, int b) { ... };end with};? - What is the difference between
sayHiandsayHi()? - When can a variable holding a function receive a different function?
- What does
forEachdo with the function you pass it?
Key Takeaways
=> expressionis a short body meaning{ return expression; }.- An arrow body is one expression — no
return,if, or loops; use? :or a switch expression for choices, and braces for anything longer. voidfunctions can use arrows too;=>then just means "the body is this expression".- An anonymous function has parameters and a body but no name.
- Stored in a variable, it is called with parentheses like any function — and every argument is still type-checked.
- A variable can be given a new function of the same type; that is the reason to store one.
- A function written directly as an argument, as with
forEach, needs no name at all. - Name fixed jobs, type stored functions' parameters, and never put braces after
=>.
What's Next?
Lecture 035 — Functions as First-Class Objects. In this lecture a function sat inside a
variable and got swapped for another, and Dart described it as String Function(String).
That is no trick: in Dart a function is a value, like a number or a string. Next we see
what follows from that — writing function types yourself, and passing named functions around
like any other value.