Functions
Reusable Blocks of Power
Open interactive version (quiz + challenge)Real-world analogy
Functions are like recipes in a cookbook. Instead of explaining how to make pancakes every time someone asks, you write the recipe ONCE and just say 'follow the pancake recipe.' In code, instead of writing the same logic over and over, you put it in a function and call it by name whenever you need it. Write once, use everywhere!
What is it?
Functions are reusable blocks of code that take inputs (parameters), perform operations, and optionally return outputs. Dart supports positional and named parameters, optional parameters with defaults, arrow functions for concise syntax, first-class functions (functions as values), anonymous functions (lambdas), and typedefs for function type aliases.
Real-world relevance
Functions are the building blocks of all software. In the team_mvp_kit project, every API call, every state update, every UI builder is a function. Well-designed functions are small, do one thing, and have clear names. The best code reads like a story: fetchUser(), validateEmail(), showError().
Key points
- Defining and Calling Functions — A function is a reusable block of code with a name. Define it with a return type, name, and parameters. Call it by name with parentheses. The function runs its code and optionally returns a result.
- Parameters and Arguments — Parameters are the variables a function expects. Arguments are the actual values you pass when calling it. Dart has positional parameters (by order) and named parameters (by name). Named parameters use curly braces {}.
- Return Types — The return type comes before the function name. It tells Dart what kind of value the function gives back. 'void' means nothing is returned. Always specify return types for clarity and type safety.
- Arrow Functions => — For functions with a single expression, use the => arrow syntax. It is a shortcut that skips the curly braces and return keyword. The expression after => is automatically returned. Clean and concise!
- Optional Parameters — Square brackets [] make positional parameters optional. They get a default value or null. Named parameters in {} are optional by default unless marked 'required'. This gives callers flexibility.
- Functions as First-Class Objects — In Dart, functions are values. You can store them in variables, pass them to other functions, and return them from functions. This is called 'first-class functions' and is incredibly powerful for callbacks and functional programming.
- Anonymous Functions (Lambdas) — Anonymous functions have no name. They are used inline, often as callbacks for methods like map(), where(), forEach(), and sort(). They are the functions you pass directly without defining them separately.
- Typedef - Function Type Aliases — typedef creates a name for a function type. Instead of writing int Function(int, int) everywhere, you define typedef MathOp = int Function(int, int) once and use MathOp as the type. Cleaner and more readable!
- Recursive Functions — A recursive function calls itself. Every recursive function needs a base case (when to stop) to avoid infinite loops. Recursion is elegant for problems like factorials, tree traversal, and divide-and-conquer algorithms.
Code example
void main() {
// Basic function with return type
print(greet('Flutter')); // Hello, Flutter!
print(greet('Dart')); // Hello, Dart!
// Arrow function
print(square(5)); // 25
print(square(12)); // 144
// Named parameters
printInfo(name: 'Alice', age: 25);
printInfo(name: 'Bob'); // uses default age
// Optional positional parameters
print(buildUrl('api.com', 'users')); // https://api.com/users
print(buildUrl('api.com')); // https://api.com
// Functions as values
var numbers = [1, 2, 3, 4, 5];
var result = applyToAll(numbers, (n) => n * n);
print(result); // [1, 4, 9, 16, 25]
// Higher-order function usage
var evens = numbers.where(isEven).toList();
print('Evens: $evens'); // [2, 4]
// Chaining functional methods
var total = numbers
.where((n) => n > 2)
.map((n) => n * 10)
.reduce((a, b) => a + b);
print('Total: $total'); // 120 (30 + 40 + 50)
}
// Named function with return type
String greet(String name) {
return 'Hello, $name!';
}
// Arrow function
int square(int n) => n * n;
// Named parameters with defaults
void printInfo({required String name, int age = 0}) {
print('Name: $name, Age: $age');
}
// Optional positional parameters
String buildUrl(String host, [String? path]) {
var url = 'https://$host';
if (path != null) url += '/$path';
return url;
}
// Higher-order function (takes a function as parameter)
List<int> applyToAll(List<int> items, int Function(int) transform) {
return items.map(transform).toList();
}
// Can be passed as a value
bool isEven(int n) => n % 2 == 0;Line-by-line walkthrough
- 1. The main function starts
- 2. A comment for basic functions
- 3. Calling greet('Flutter') and printing the result
- 4. Calling greet('Dart') and printing the result
- 5.
- 6. A comment for arrow functions
- 7. Calling square(5) -- returns 25
- 8. Calling square(12) -- returns 144
- 9.
- 10. A comment for named parameters
- 11. Calling printInfo with both name and age specified
- 12. Calling printInfo with only name -- age uses default value 0
- 13.
- 14. A comment for optional positional parameters
- 15. buildUrl with both host and path -- returns full URL
- 16. buildUrl with only host -- path is null, returns base URL
- 17.
- 18. A comment for functions as values
- 19. Creating a list of numbers 1 through 5
- 20. applyToAll takes the list and an anonymous squaring function
- 21. Printing the result -- each number squared
- 22.
- 23. A comment for higher-order function usage
- 24. where() takes the isEven function by name (no parentheses!) to filter
- 25. Printing the even numbers
- 26.
- 27. A comment for chaining functional methods
- 28. Starting with the numbers list
- 29. where keeps only numbers greater than 2
- 30. map multiplies each by 10
- 31. reduce adds them all together
- 32. Printing the total: 30 + 40 + 50 = 120
- 33. Closing the main function
- 34.
- 35. A comment for the greet function definition
- 36. greet takes a String name and returns a String
- 37. Returns 'Hello, ' plus the name with an exclamation mark
- 38. Closing the function
- 39.
- 40. A comment for the arrow function
- 41. square takes an int and returns its square using => syntax
- 42.
- 43. A comment for named parameters
- 44. printInfo has a required name and optional age with default 0
- 45. Printing the formatted info string
- 46. Closing the function
- 47.
- 48. A comment for optional positional parameters
- 49. buildUrl takes a required host and optional path
- 50. Building the base URL with https
- 51. If path is provided, append it with a slash
- 52. Returning the complete URL
- 53. Closing the function
- 54.
- 55. A comment for the higher-order function
- 56. applyToAll takes a list and a transform function
- 57. Uses map to apply the transform to each item and returns a list
- 58. Closing the function
- 59.
- 60. A comment for the function value
- 61. isEven is a named function that returns true if n is even
Spot the bug
void main() {
print(add(3, 5));
}
String add(int a, int b) {
return a + b;
}Need a hint?
Look at the return type of the function versus what it actually returns...
Show answer
The function add() is declared to return String, but a + b (where a and b are int) returns an int. Fix: change the return type from String to int: int add(int a, int b) { return a + b; }
Explain like I'm 5
Functions are like magic spells with names. You create a spell once: 'Abracadabra -- double any number!' Then whenever you need to double a number, you just say the spell name instead of explaining the whole magic trick again. The ingredients you give the spell (like the number to double) are parameters. What the spell gives back (the doubled number) is the return value. And the cool part? You can teach one spell to another spell -- that is first-class functions!
Fun fact
The concept of functions in programming comes from mathematics (f(x) = x + 1). But the idea of 'first-class functions' -- treating functions as values -- was invented in the 1950s with the LISP programming language. Dart, JavaScript, Python, and many modern languages all support this, making code more flexible and powerful!
Hands-on challenge
Write three functions: (1) A function 'celsiusToFahrenheit' that converts Celsius to Fahrenheit (F = C * 9/5 + 32). (2) A function 'isPositive' that returns true if a number is greater than 0. (3) A function 'applyDiscount' with named parameters: price (required) and percent (default 10). Test all three!
More resources
- Dart Functions (Dart Official)
- Dart Typedefs (Dart Official)
- Effective Dart: Usage (Dart Official)