In Dart, higher-order functions are functions that either:
Take another function as a parameter, or
Return a function as their result.
Higher-order functions are essential in functional programming and are widely used for tasks like iteration, transformation, and composition.
1. A Function That Takes Another Function as a Parameter
You can pass functions as arguments to other functions. For example:
void performOperation(int a, int b, int Function(int, int) operation)
{
print("Result: ${operation(a, b)}");
}
void main() {
performOperation(4, 5, (x, y) => x + y); // Output: Result: 9
performOperation(10, 3, (x, y) => x - y); // Output: Result: 7
}
Here, the performOperation function takes a Function parameter operation, which can be any function that matches the signature (int, int) => int.
2. A Function That Returns Another Function
Functions in Dart can return other functions. For example:
Function multiplier(int factor) {
return (int x) => x * factor;
}
void main() {
var triple = multiplier(3); // Returns a function that multiplies by 3
print(triple(4)); // Output: 12
var doubleIt = multiplier(2);
print(doubleIt(5)); // Output: 10
}
Here, multiplier returns a function that multiplies its input by the given factor.
Dart provides built-in higher-order functions for collections, such as forEach, map, where, reduce, and fold.
1. forEach
Executes a function for each element in a collection.
void main() {
var numbers = [1, 2, 3, 4];
numbers.forEach((number) => print(number));
// Output:
// 1
// 2
// 3
// 4
}
2. map
Transforms each element in a collection and returns a new collection.
void main() {
var numbers = [1, 2, 3];
var doubled = numbers.map((number) => number * 2).toList();
print(doubled); // Output: [2, 4, 6]
}
3. where
Filters a collection based on a condition and returns a new collection.
void main() {
var numbers = [1, 2, 3, 4, 5];
var evens = numbers.where((number) => number.isEven).toList();
print(evens); // Output: [2, 4]
}
4. reduce
Reduces a collection to a single value by applying a function repeatedly.
void main() {
var numbers = [1, 2, 3, 4];
var sum = numbers.reduce((a, b) => a + b);
print(sum); // Output: 10
}
5. fold
Similar to reduce, but allows you to specify an initial value.
void main() {
var numbers = [1, 2, 3, 4];
var sum = numbers.fold(0, (prev, element) => prev + element);
print(sum); // Output: 10
}
Code reusability: You can reuse functions as arguments or return values.
Readability: Higher-order functions make the intent clear, especially when working with collections.
Functional programming: They enable functional programming techniques, such as immutability and chaining.
Here’s a collection of 20 programs that showcase the use of Higher-Order Functions in Dart. Each example highlights a different way higher-order functions can be used.
void execute(Function action) {
action();
}
void main() {
execute(() => print("Hello, Dart!")); // Output: Hello, Dart!
}
Function greet(String name) {
return () => print("Hello, $name!");
}
void main() {
var greetJohn = greet("John");
greetJohn(); // Output: Hello, John!
}
void main() {
var numbers = [1, 2, 3];
var squares = numbers.map((number) => number * number).toList();
print(squares); // Output: [1, 4, 9]
}
void main() {
var numbers = [10, 15, 20, 25];
var evens = numbers.where((number) => number.isEven).toList();
print(evens); // Output: [10, 20]
}
void main() {
var numbers = [1, 2, 3, 4];
var sum = numbers.reduce((a, b) => a + b);
print(sum); // Output: 10
}
void main() {
var numbers = [1, 2, 3];
var product = numbers.fold(1, (prev, element) => prev * element);
print(product); // Output: 6
}
List<int> filter(List<int> list, bool Function(int) condition) {
return list.where(condition).toList();
}
void main() {
var numbers = [1, 2, 3, 4, 5];
print(filter(numbers, (n) => n > 3)); // Output: [4, 5]
}
void main() {
var numbers = [1, 2, 3, 4];
var result = numbers.where((n) => n.isEven).map((n) => n * n).toList();
print(result); // Output: [4, 16]
}
void main() {
var fruits = ["apple", "banana", "cherry"];
fruits.sort((a, b) => b.length.compareTo(a.length));
print(fruits); // Output: [banana, cherry, apple]
}
import 'dart:async';
void delayExecution(Duration duration, Function action) {
Timer(duration, action);
}
void main() {
delayExecution(Duration(seconds: 2), () => print("Action executed!"));
}
Function wrapFunction(Function fn) {
return () => print("Wrapped: ${fn()}");
}
void main() {
var wrapped = wrapFunction(() => "Hello");
wrapped(); // Output: Wrapped: Hello
}
void main() {
var numbers = [1, 2, 3];
var hasEven = numbers.any((n) => n.isEven);
print(hasEven); // Output: true
}
void main() {
var numbers = [2, 4, 6];
var allEven = numbers.every((n) => n.isEven);
print(allEven); // Output: true
}
void partition(List<int> list, bool Function(int) condition) {
var pass = list.where(condition).toList();
var fail = list.where((x) => !condition(x)).toList();
print("Pass: $pass, Fail: $fail");
}
void main() {
partition([1, 2, 3, 4], (n) => n.isEven);
// Output: Pass: [2, 4], Fail: [1, 3]
}
List<T> transform<T>(List<int> list, T Function(int) transformer) {
return list.map(transformer).toList();
}
void main() {
var result = transform([1, 2, 3], (n) => "Number $n");
print(result); // Output: [Number 1, Number 2, Number 3]
}
Function compose(Function f, Function g) {
return (x) => f(g(x));
}
void main() {
var doubleIt = (int x) => x * 2;
var square = (int x) => x * x;
var doubleThenSquare = compose(square, doubleIt);
print(doubleThenSquare(3)); // Output: 36
}
void retry(Function action, int attempts) {
for (int i = 0; i < attempts; i++) {
try {
action();
return;
} catch (e) {
print("Attempt ${i + 1} failed.");
}
}
}
void main() {
retry(() => print("Trying..."), 3);
}
void conditionalExecute(bool condition, Function action) {
if (condition) action();
}
void main() {
conditionalExecute(5 > 3, () => print("Condition met!")); // Output: Condition met!
}
Function debounce(Function action, Duration delay) {
Timer? timer;
return () {
if (timer != null) timer!.cancel();
timer = Timer(delay, action);
};
}
void main() {
var debouncedAction = debounce(() => print("Debounced!"), Duration(seconds: 2));
debouncedAction();
debouncedAction(); // Only the last one will execute
}
A function can accept other functions as parameters or return a function.
void main() {
// A function that accepts a function as a parameter
void applyFunction(int num, Function operation) {
print("Result: ${operation(num)}");
}
// Passing different functions as arguments
applyFunction(5, (x) => x * x); // Passing a lambda function
applyFunction(5, (x) => x + 10); // Another lambda function
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------
A higher-order function is a function that either takes one or more functions as arguments or returns a function as its result. These functions are powerful for building flexible, reusable code.
void main() {
List<int> numbers = [1, 2, 3, 4];
List<int> squares = numbers.map((n) => n * n).toList();
print(squares); // Output: [1, 4, 9, 16]
}
void main() {
List<int> numbers = [1, 2, 3, 4, 5, 6];
List<int> evens = numbers.where((n) => n % 2 == 0).toList();
print(evens); // Output: [2, 4, 6]
}
void main() {
void performOperation(int a, int b, int Function(int, int) operation) {
print("Result: ${operation(a, b)}");
}
performOperation(5, 3, (a, b) => a + b); // Output: Result: 8
performOperation(5, 3, (a, b) => a * b); // Output: Result: 15
}
void main() {
List<int> numbers = [1, 2, 3, 4];
int sum = numbers.reduce((a, b) => a + b);
print("Sum: $sum"); // Output: Sum: 10
}
void main() {
Function multiplier(int factor) {
return (int x) => x * factor;
}
var triple = multiplier(3);
print(triple(4)); // Output: 12
}
void main() {
List<String> names = ["Alice", "Bob", "Charlie"];
names.forEach((name) => print("Hello, $name!"));
// Output:
// Hello, Alice!
// Hello, Bob!
// Hello, Charlie!
}
void main() {
List<String> words = ["dart", "flutter", "programming"];
List<String> capitalizedWords = words.map((word) => word.toUpperCase()).toList();
print(capitalizedWords); // Output: [DART, FLUTTER, PROGRAMMING]
}
void main() {
int applyTwice(int x, int Function(int) f) => f(f(x));
int doubleValue(int x) => x * 2;
print(applyTwice(5, doubleValue)); // Output: 20
}
void main() {
List<int> numbers = [10, 5, 20, 3];
numbers.sort((a, b) => b.compareTo(a)); // Sorting in descending order
print(numbers); // Output: [20, 10, 5, 3]
}
void main() {
void repeatTask(int times, Function task) {
for (int i = 0; i < times; i++) {
task();
}
}
repeatTask(3, () => print("Hello!"));
// Output:
// Hello!
// Hello!
// Hello!
}
These examples demonstrate the use of higher-order functions in Dart. Functions like map, where, forEach, and reduce are examples of built-in higher-order functions. Additionally, creating custom higher-order functions, such as applyTwice or repeatTask, adds flexibility to your code.