Functions in Dart
By Syncfusion®, Inc. · Last updated
How to write and call functions, return values, positional, optional and named parameters, arrow and anonymous functions, closures, recursion and scope.
What Is a Function?
Function = a named block of code that does one job. You can run it again and again by its name.
For example:
greet()prints a welcome messageaddGst(price)works out a price with taxisPass(marks)answerstrueorfalse
You have already used functions: main() and print().
Simple lesson: a function is a named piece of work you can reuse.
A Real-World Example
Think of a pressure cooker.
- You put in rice and water (the inputs).
- It does the same job every time: cook.
- It gives back cooked rice (the output).
- You do not need to know what happens inside. You just use it.
A function is that machine: inputs go in, it does its job, and an answer comes out.
Every Run box on this page runs on the course's Dart runner in your browser.
Some boxes fail on purpose, to show a real error.
What You Will Learn
In this lesson, you will learn:
- How to define and call a function, and get a value back with
return. - Positional, optional and named parameters, and default values.
- Anonymous functions and arrow functions.
- Higher-order functions, callbacks and closures.
- Recursion and scope.
Function Fundamentals
Why Functions Are Used
- Reuse: write the code once, call it many times.
- Fewer mistakes: fix a bug in one place, and every call is fixed.
- Easy to read:
printReportCard()says what it does. - Small pieces: a big program becomes many small, simple functions.
Defining a Function
returnType functionName(parameters) {
// body
}
- Return type = the type of value it gives back.
void= nothing. - Function name = lowerCamelCase, usually a verb:
printHeader,addMarks. - Parameters = the inputs, inside
( ). - Body = the code, inside
{ }.
Calling a Function
Call = run a function by writing its name and ( ).
Define once, call many times
void printLine() {
print('------------------------');
}
void main() {
printLine();
print('GREEN VALLEY SCHOOL');
printLine();
print('Report Card 2026');
printLine();
}
printLine was written once, and called three times.
Simple lesson: define a function once, then call it by name whenever you need it.
Return Values
return
return = send a value back to the caller, and stop the function.
Return value = the value a function gives back.
Call, run, return
Parameter = the name in the function's definition, like a.
Argument = the actual value you pass in a call, like 78.
Returning Different Types
Functions that answer questions
bool isPass(int marks) {
return marks >= 35;
}
String grade(int marks) {
if (marks >= 90) return 'A';
if (marks >= 75) return 'B';
return 'C';
}
void main() {
print(isPass(42));
print(isPass(20));
print(grade(81));
}
return ends the function straight away. Code after it in that path does not run.
void Functions
void = the function gives nothing back. It just does something, like printing.
A void function does a job
void welcome(String name) {
print('Welcome to Green Valley, $name!');
}
void main() {
welcome('Kavya');
welcome('Imran');
}
Simple lesson: return hands a value back, and void means the function only does a job.
Function Parameters
Required Positional Parameters
Positional parameter = an input matched by its position in the call.
- The first argument goes to the first parameter, and so on.
- All of them must be given, in the right order.
Order matters
void showMarks(String name, int marks) {
print('$name scored $marks.');
}
void main() {
showMarks('Asha', 88);
showMarks('Ravi', 74);
}
Optional Positional Parameters
Optional positional parameter = an input in [ ] that the caller may leave out.
An optional section
void showClass(String name, [String? section]) {
print('$name, section: ${section ?? 'not given'}');
}
void main() {
showClass('Asha', '8B');
showClass('Ravi');
}
- Optional parameters go last, inside
[ ]. - If one is left out, it is
null, so its type needs?(see Null Safety).
Named Parameters
Named parameter = an input in { } that the caller passes by name.
- In the call, write
name: value. - The order does not matter.
- Named parameters are optional, unless marked
required.
Named parameters
void addStudent({required String name, required int rollNumber, String? house}) {
print('$rollNumber: $name, house: ${house ?? 'none'}');
}
void main() {
addStudent(name: 'Meena', rollNumber: 12, house: 'Tagore');
addStudent(rollNumber: 13, name: 'Kiran');
}
Named parameters make calls easy to read. addStudent(name: 'Meena', rollNumber: 12) explains itself.
Default Values
Default value = the value a parameter uses when the caller leaves it out.
Default values
void orderLunch(String item, {int quantity = 1, bool extraSpicy = false}) {
print('$quantity x $item, extra spicy: $extraSpicy');
}
void main() {
orderLunch('Samosa');
orderLunch('Dosa', quantity: 2);
orderLunch('Pav Bhaji', extraSpicy: true, quantity: 3);
}
Compare the kinds of parameters
Simple lesson: positional inputs go by order, named inputs go by name, and defaults fill the gaps.
Anonymous Functions
Anonymous function = a function with no name. Also called a function expression.
(parameters) {
// body
}
You can store it in a variable, or pass it straight to another function.
A function without a name
void main() {
var shout = (String text) {
return text.toUpperCase() + '!';
};
print(shout('jai hind'));
var marks = [78, 92, 65];
marks.forEach((m) {
print('Mark: $m');
});
}
Simple lesson: an anonymous function is a function you use right where you write it.
Arrow Functions
Arrow syntax (=>) = a short way to write a function whose body is one expression.
=> expr means { return expr; }.
Arrow functions
int square(int n) => n * n;
bool isEven(int n) => n % 2 == 0;
String greet(String name) => 'Hello, $name!';
void main() {
print(square(9));
print(isEven(14));
print(greet('Zoya'));
var twice = (int n) => n * 2;
print(twice(21));
}
Single-expression function = a function that only works out one value. Arrows are made for them.
- Use
=>for one expression. - Use
{ }when you need several statements.
Dart's own code style uses => for every function whose body is just one return.
You will see it everywhere in Flutter code, so it is worth getting used to now.
Simple lesson: => value is short for { return value; }.
Higher-Order Functions
Higher-order function = a function that takes another function as an input, or gives one back.
Functions as Values
In Dart, a function is a value, like a number. You can store it in a variable.
Functions as Parameters and Callbacks
Callback = a function you pass to another function, so it can call it later.
Passing a function as an input
int addGrace(int m) => m + 5;
int doubleIt(int m) => m * 2;
void changeAll(List<int> marks, int Function(int) rule) {
for (var m in marks) {
print(rule(m));
}
}
void main() {
var marks = [30, 50];
changeAll(marks, addGrace);
changeAll(marks, doubleIt);
changeAll(marks, (m) => m - 1);
}
int Function(int)= the type "a function that takes anintand gives anint".changeAlldoes not know the rule. The caller decides it.- You will use this a lot in Working with Iterables, with
mapandwhere.
Simple lesson: a higher-order function takes a function as an input, so the caller can choose the behaviour.
Closures
Closure = a function that remembers the variables around it, even after that code has finished.
Lexical scope = a function can use the variables of the place where it was written.
A counter that remembers
Function makeTokenCounter() {
var token = 0;
return () {
token++;
return 'Token $token';
};
}
void main() {
var nextToken = makeTokenCounter();
print(nextToken());
print(nextToken());
print(nextToken());
}
makeTokenCounterfinished long ago.- But the returned function still remembers
token, and keeps counting.
Simple lesson: a closure carries its own variables with it, like a backpack.
Recursion
Recursive function = a function that calls itself.
Every recursive function needs two parts:
- Base case = when to stop. No more calls.
- Recursive case = call itself with a smaller problem.
Factorial Example
Factorial = 5! = 5 × 4 × 3 × 2 × 1 = 120.
Notice: 5! = 5 × 4!, and 4! = 4 × 3!, and so on, until 1! = 1.
Factorial with recursion
int factorial(int n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
void main() {
print(factorial(5));
print(factorial(3));
}
- Base case:
n <= 1returns1. - Recursive case:
n * factorial(n - 1). Each call has a smallern.
Without a base case, the function calls itself forever, and the program crashes with a Stack Overflow.
Simple lesson: recursion solves a problem by solving a smaller copy of it, until it reaches a base case.
Function Scope
Scope = the part of the code where a variable can be used.
- Local variable = made inside a function. It exists only inside it.
- Global variable = made outside every function, at the top level. Every function can use it.
Scope Rules
- Code inside a block can see variables from outside it.
- Code outside a block cannot see variables made inside it.
- A local variable disappears when its function ends.
Global and local variables
var school = 'Green Valley';
void showTotal() {
var total = 92 + 88;
print('$school: total $total');
}
void main() {
showTotal();
print('School: $school');
}
total lives only inside showTotal. Try to use it outside:
A local variable cannot be seen outside
void showTotal() {
var total = 92 + 88;
}
void main() {
print(total);
}
Dart says: Undefined name 'total'.
Easy way to remember
- Parameters = what goes in.
return= what comes out. =>= a one-line function.- Local variables stay inside their function.
- Prefer local variables. Global ones can be changed from anywhere, which causes bugs.
Simple lesson: a variable lives inside the { } where it was made, and inner code can see outward.
TL;DR
Function = a named, reusable block. Call it with
name().returngives a value back.voidgives nothing.
Parameters:
- Positional = by order. Optional
[ ]= may be left out. - Named
{ }= by name, optional unlessrequired. Defaults fill gaps.
- Positional = by order. Optional
- Anonymous function = no name. Arrow
=>= one-expression body. Higher-order function = takes or returns a function. Callback = a function passed in.
- Closure = a function that remembers its surrounding variables.
Recursion = a function calls itself, with a base case to stop.
- Scope = local inside a function, global at the top level.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
Forgetting return | The last value is returned | Write return value; | The function gives back null, or an error. |
Using a void result | void functions give a value | They give nothing | This expression has a type of 'void'. |
| Arguments in the wrong order | Dart matches by name | Positional arguments go by order | The wrong values in the wrong places. |
Leaving out a required named argument | All named ones are optional | required ones must be given | Required named parameter must be provided. |
| No base case | Recursion stops by itself | Every recursion needs a base case | Stack Overflow. |
| Using a local variable outside | Variables are visible everywhere | Locals live inside their function | Undefined name. |
=> with several statements | Arrows can hold a block | => takes one expression | A syntax error. |
Check Yourself
Exercises
What to Remember
- A function is a named, reusable block.
returngives a value back, andvoidgives nothing. - Positional inputs go by order,
[ ]makes them optional, and{ }makes them named. =>is a one-expression function, and an anonymous function has no name.- Functions can be passed to other functions, and closures remember their variables.
- Recursion needs a base case. A local variable lives only inside its function.
Next: Lists. You will learn to store many values in one variable, in order.