Dart Higher-Order Functions
Functions that work with other functions as parameters or return values
🔝 What are Higher-Order Functions?
Higher-order functions in Dart are functions that either take other functions as parameters or return functions as results. They enable powerful functional programming patterns and code reusability.
// Higher-order function that takes a function as parameter
void executeOperation(int a, int b, Function(int, int) operation) {
var result = operation(a, b);
print('Result: $result');
}
// Using the higher-order function
executeOperation(5, 3, (x, y) => x + y); // Addition
executeOperation(5, 3, (x, y) => x * y); // Multiplication
Output:
Result: 8
Result: 15
Higher-Order Function Types
Accept Functions
Take functions as parameters
void process(List list, Function(int) fn) {
list.forEach(fn);
}
Return Functions
Create and return new functions
Function createAdder(int n) {
return (int x) => x + n;
}
Transform Data
Map, filter, and reduce operations
var doubled = numbers.map((n) => n * 2);
var evens = numbers.where((n) => n % 2 == 0);
Compose Logic
Combine functions for complex operations
var pipeline = compose(validate, transform, save);
pipeline(data);
🔹 Functions as Parameters
Passing functions as arguments to other functions:
// Higher-order function that applies operation to two numbers
T calculate(T a, T b, T Function(T, T) operation) {
return operation(a, b);
}
// Different operations
int add(int x, int y) => x + y;
int multiply(int x, int y) => x * y;
double divide(double x, double y) => x / y;
// Function that processes a list with custom logic
void processItems(List items, void Function(T) processor) {
print('Processing ${items.length} items...');
for (var item in items) {
processor(item);
}
}
void main() {
// Using calculate with different operations
print('Addition: ${calculate(10, 5, add)}');
print('Multiplication: ${calculate(10, 5, multiply)}');
print('Division: ${calculate(10.0, 5.0, divide)}');
// Using anonymous functions
print('Subtraction: ${calculate(10, 5, (a, b) => a - b)}');
// Processing items
var names = ['Alice', 'Bob', 'Charlie'];
processItems(names, (name) => print('Hello, $name!'));
}
Output:
Addition: 15
Multiplication: 50
Division: 2.0
Subtraction: 5
Processing 3 items...
Hello, Alice!
Hello, Bob!
Hello, Charlie!
🔹 Functions that Return Functions
Creating function factories and closures:
// Function factory - returns customized functions
Function createValidator(int minLength, int maxLength) {
return (String input) {
if (input.length < minLength) {
return 'Too short! Minimum $minLength characters.';
}
if (input.length > maxLength) {
return 'Too long! Maximum $maxLength characters.';
}
return 'Valid input!';
};
}
// Function that creates mathematical operations
Function createMathOperation(String operation) {
switch (operation) {
case 'square':
return (double n) => n * n;
case 'cube':
return (double n) => n * n * n;
case 'double':
return (double n) => n * 2;
default:
return (double n) => n;
}
}
void main() {
// Create custom validators
var usernameValidator = createValidator(3, 15);
var passwordValidator = createValidator(8, 50);
print('Username "ab": ${usernameValidator("ab")}');
print('Username "alice": ${usernameValidator("alice")}');
print('Password "123": ${passwordValidator("123")}');
print('Password "mypassword123": ${passwordValidator("mypassword123")}');
// Create math operations
var square = createMathOperation('square');
var cube = createMathOperation('cube');
print('\nMath Operations:');
print('Square of 4: ${square(4)}');
print('Cube of 3: ${cube(3)}');
}
Output:
Username "ab": Too short! Minimum 3 characters.
Username "alice": Valid input!
Password "123": Too short! Minimum 8 characters.
Password "mypassword123": Valid input!
Math Operations:
Square of 4: 16.0
Cube of 3: 27.0
🔹 Built-in Higher-Order Functions
Dart provides many built-in higher-order functions for collections:
void main() {
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var words = ['apple', 'banana', 'cherry', 'date', 'elderberry'];
// map - transform each element
var squares = numbers.map((n) => n * n).toList();
var upperWords = words.map((w) => w.toUpperCase()).toList();
// where - filter elements
var evens = numbers.where((n) => n % 2 == 0).toList();
var longWords = words.where((w) => w.length > 5).toList();
// fold/reduce - combine elements
var sum = numbers.fold(0, (prev, curr) => prev + curr);
var product = numbers.fold(1, (prev, curr) => prev * curr);
var longest = words.reduce((a, b) => a.length > b.length ? a : b);
// any/every - check conditions
bool hasEven = numbers.any((n) => n % 2 == 0);
bool allPositive = numbers.every((n) => n > 0);
print('Original: $numbers');
print('Squares: $squares');
print('Upper words: $upperWords');
print('Even numbers: $evens');
print('Long words: $longWords');
print('Sum: $sum');
print('Product: $product');
print('Longest word: $longest');
print('Has even: $hasEven');
print('All positive: $allPositive');
}
Output:
Original: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Squares: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Upper words: [APPLE, BANANA, CHERRY, DATE, ELDERBERRY]
Even numbers: [2, 4, 6, 8, 10]
Long words: [banana, cherry, elderberry]
Sum: 55
Product: 3628800
Longest word: elderberry
Has even: true
All positive: true
🔹 Real-World Example: Data Pipeline
Building a data processing pipeline with higher-order functions:
// Data processing pipeline
class DataProcessor {
// Higher-order function that applies multiple transformations
static List pipeline(List data, List transformations) {
return transformations.fold(data, (currentData, transform) {
return currentData.map(transform).toList();
});
}
// Higher-order function for conditional processing
static List conditionalProcess(
List data,
bool Function(T) condition,
T Function(T) processor
) {
return data.map((item) => condition(item) ? processor(item) : item).toList();
}
}
void main() {
var rawData = [' hello ', ' WORLD ', ' dart ', ' PROGRAMMING '];
print('Raw data: $rawData');
// Create transformation functions
var trim = (String s) => s.trim();
var toLowerCase = (String s) => s.toLowerCase();
var capitalize = (String s) => s.isEmpty ? s :
s[0].toUpperCase() + s.substring(1);
// Apply pipeline
var processed = DataProcessor.pipeline(rawData, [trim, toLowerCase, capitalize]);
print('Processed: $processed');
// Conditional processing
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var result = DataProcessor.conditionalProcess(
numbers,
(n) => n % 2 == 0, // condition: is even
(n) => n * n // processor: square it
);
print('Numbers: $numbers');
print('Squared evens: $result');
}
Output:
Raw data: [ hello , WORLD , dart , PROGRAMMING ]
Processed: [Hello, World, Dart, Programming]
Numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Squared evens: [1, 4, 3, 16, 5, 36, 7, 64, 9, 100]