Sitemap

Functional Programming in Dart

4 min readMar 12, 2025

--

Dart is primarily an object-oriented language, but it also supports functional programming (FP) principles. Functional programming is a paradigm that treats computation as the evaluation of pure functions and avoids shared mutable state.

In this guide, we’ll explore functional programming in Dart, covering higher-order functions, first-class functions, pure functions, immutability, and more.

🔹 Why Use Functional Programming in Dart?

✅ Improved Readability — Functions are self-contained and predictable.
✅ Easier Debugging & Testing — No side effects, making unit testing simpler.
✅ Concurrency-Friendly — Avoids race conditions in multithreading.
✅ Less Complexity — Less dependency on mutable state and class hierarchies.

1️⃣ First-Class Functions in Dart

Dart treats functions as first-class citizens, meaning you can:
✔️ Assign functions to variables.
✔️ Pass functions as arguments.
✔️ Return functions from other functions.

Example: Assigning Functions to Variables

void greet(String name) {
print("Hello, $name!");
}

void main() {
var sayHello = greet; // Assign function to variable
sayHello("Alice");
}

Example: Passing Functions as Arguments

void executeFunction(Function action) {
action();
}

void sayHi() {
print("Hi there!");
}

void main() {
executeFunction(sayHi); // Passing function as an argument
}

2️⃣ Higher-Order Functions (HOFs)

A higher-order function is a function that takes another function as a parameter or returns a function.

Example: Function Returning a Function

Function multiplyBy(int factor) {
return (int number) => number * factor;
}

void main() {
var doubleNumber = multiplyBy(2);
print(doubleNumber(5)); // Output: 10
}

3️⃣ Anonymous Functions (Lambda or Arrow Functions)

Dart supports anonymous functions (also called lambda functions or closures).

Example: Lambda Function (Short Syntax)

var square = (int x) => x * x;

void main() {
print(square(4)); // Output: 16
}

💡 Note: {} can also be used:

var add = (int a, int b) {
return a + b;
};
print(add(3, 4)); // Output: 7

4️⃣ Pure Functions (No Side Effects)

A pure function:
✔️ Always returns the same output for the same input.
✔️ Has no side effects (doesn’t modify external state).

Example of a Pure Function

int add(int a, int b) {
return a + b;
}

void main() {
print(add(3, 5)); // Output: 8 (Always predictable)
}

🚫 Impure Function Example (Modifies External State)

int counter = 0;

void increment() {
counter++;
} // ❌ Modifies global state (impure function)

5️⃣ Immutability in Functional Programming

Immutability means variables and objects should not be modified after creation.

Example: Immutable Variables with final & const

final name = "Alice";  // Cannot be reassigned
const pi = 3.14; // Compile-time constant

Example: Immutability in Data Structures (Using List.unmodifiable)

void main() {
final List<int> numbers = List.unmodifiable([1, 2, 3, 4]);

numbers.add(5); // ❌ This will throw an error
}

6️⃣ Functional Collections: map(), where(), reduce(), fold()

Dart provides functional operations on lists like map, filter (where), reduce, and fold to process collections efficiently.

Example: Using map() for Transformation

void main() {
List<int> numbers = [1, 2, 3, 4];
List<int> doubled = numbers.map((num) => num * 2).toList();

print(doubled); // Output: [2, 4, 6, 8]
}

Example: Using where() for Filtering

void main() {
List<int> numbers = [10, 20, 30, 40];
List<int> filtered = numbers.where((num) => num > 20).toList();

print(filtered); // Output: [30, 40]
}

Example: Using reduce() to Accumulate Values

void main() {
List<int> numbers = [1, 2, 3, 4];
int sum = numbers.reduce((a, b) => a + b);

print(sum); // Output: 10
}

Example: Using fold() with an Initial Value

void main() {
List<int> numbers = [1, 2, 3, 4];
int sum = numbers.fold(0, (prev, next) => prev + next);

print(sum); // Output: 10
}

7️⃣ Currying in Dart (Partial Application)

Currying allows breaking down a function into multiple functions, each taking one parameter at a time.

Function add(int a) {
return (int b) => a + b;
}

void main() {
var addFive = add(5);
print(addFive(3)); // Output: 8
}

8️⃣ Functional Reactive Programming (FRP) in Dart

Flutter’s state management solutions like Riverpod, Bloc, and RxDart are inspired by Functional Reactive Programming (FRP).

Get Punith S Uppar’s stories in your inbox

Join Medium for free to get updates from this writer.

Example using Stream (Reactive Programming):

Stream<int> countStream(int max) async* {
for (int i = 1; i <= max; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}

void main() async {
await for (int value in countStream(5)) {
print(value); // Emits 1, 2, 3, 4, 5 with a delay
}
}

🎯 Key Takeaways

✔️ Dart supports Functional Programming with higher-order functions, lambdas, and immutability.
✔️ Pure functions make code more predictable and testable.
✔️ List operations (map, where, reduce, fold) help process collections functionally.
✔️ Streams enable Functional Reactive Programming (FRP) in Dart.

By leveraging functional programming principles, you can write cleaner, more efficient, and maintainable Dart code.

📌 What’s Next?

Thinking of integrating functional programming in your Flutter app? Let me know in the comments! 😊

--

--

Punith S Uppar
Punith S Uppar

Written by Punith S Uppar

Experienced Flutter Dev & No-Code/Low-Code Flutter Flow Dev|| Transforming Ideas into Powerful Mobile & Web Solutions || Effective Communicator Click📲 puni