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]

🧠 Test Your Knowledge

What makes a function a "higher-order" function?