Problem Statement
What are pure functions? Explain their benefits and provide examples of pure and impure functions.
Explanation
Pure functions are functions that satisfy two conditions: they return the same output for the same input and have no side effects.
First condition: Deterministic behavior:
Given the same arguments, pure function always returns the same result. The output depends only on input parameters. No dependency on external state or global variables. Predictable and reliable behavior.
Second condition: No side effects:
Does not modify external state or global variables. Does not mutate function arguments. Does not perform I/O operations like console.log, file read write, or network requests. Does not modify DOM. Does not generate random numbers or use current time.
Benefits of pure functions:
Easier to test because behavior is predictable. Easier to debug with no hidden dependencies. Can be safely parallelized or cached with memoization. Enable referential transparency, can replace function call with its result. More maintainable and understandable code. Support functional programming patterns.
Common impure operations:
Modifying global variables. Mutating function parameters. Console logging or any I/O. Using Math.random or Date. Modifying DOM. Making API calls. Reading from or writing to files.
Making impure functions pure:
Return new values instead of modifying existing ones. Accept all dependencies as parameters. Use pure functions for calculations, separate I/O. Return new objects and arrays instead of mutating.
When impure functions are necessary:
User interaction and event handling. API calls and data fetching. Logging and debugging. File system operations. Any I/O operations.
Best practices:
Maximize pure functions in your codebase. Isolate impure code at the edges of your application. Keep business logic pure. Use pure functions for data transformations.
Understanding pure functions is fundamental to functional programming and writing maintainable code.
Code Solution
SolutionRead Only
// PURE FUNCTIONS
// Pure - same input, same output, no side effects
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // Always 5
console.log(add(2, 3)); // Always 5
// Pure - doesn't modify input
function doubleArray(arr) {
return arr.map(n => n * 2);
}
const numbers = [1, 2, 3];
const doubled = doubleArray(numbers);
console.log(numbers); // [1, 2, 3] (unchanged)
console.log(doubled); // [2, 4, 6]
// Pure - string manipulation
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}
console.log(capitalize('hello')); // 'Hello'
console.log(capitalize('hello')); // 'Hello' (same)
// Pure - object transformation
function updateUser(user, updates) {
return { ...user, ...updates }; // New object
}
const user = { name: 'John', age: 30 };
const updated = updateUser(user, { age: 31 });
console.log(user.age); // 30 (unchanged)
console.log(updated.age); // 31
// IMPURE FUNCTIONS
// Impure - modifies external variable
let total = 0;
function addToTotal(value) {
total += value; // Side effect!
return total;
}
console.log(addToTotal(5)); // 5
console.log(addToTotal(5)); // 10 (different!)
// Impure - mutates argument
function addItemImpure(arr, item) {
arr.push(item); // Mutates input!
return arr;
}
// Impure - I/O operation
function logValue(value) {
console.log(value); // Side effect!
return value;
}
// Impure - uses external state
let multiplier = 2;
function multiplyByMultiplier(n) {
return n * multiplier; // Depends on external variable
}
console.log(multiplyByMultiplier(5)); // 10
multiplier = 3;
console.log(multiplyByMultiplier(5)); // 15 (different!)
// Impure - random output
function getRandomNumber() {
return Math.random(); // Non-deterministic
}
// Impure - current time
function getCurrentTimestamp() {
return Date.now(); // Different each call
}
// CONVERTING IMPURE TO PURE
// Impure version
function discountPriceImpure(price) {
const discount = 0.1; // Hard-coded
console.log('Calculating discount'); // Side effect
return price - (price * discount);
}
// Pure version
function discountPricePure(price, discount) {
return price - (price * discount);
}
// Separate side effects
function calculateAndLog(price, discount) {
const result = discountPricePure(price, discount); // Pure
console.log('Result:', result); // Impure, but isolated
return result;
}
// REAL-WORLD EXAMPLES
// Pure - shopping cart total
function calculateTotal(items) {
return items.reduce((sum, item) => {
return sum + (item.price * item.quantity);
}, 0);
}
const cart = [
{ name: 'Book', price: 10, quantity: 2 },
{ name: 'Pen', price: 2, quantity: 5 }
];
console.log(calculateTotal(cart)); // 30
// Pure - filtering and mapping
function getActiveUserNames(users) {
return users
.filter(user => user.active)
.map(user => user.name);
}
// Pure - form validation
function validateEmail(email) {
return email.includes('@') && email.includes('.');
}
function validatePassword(password) {
return password.length >= 8;
}
function validateForm(data) {
return {
emailValid: validateEmail(data.email),
passwordValid: validatePassword(data.password)
};
}
// BENEFITS DEMONSTRATION
// 1. Easy testing
function multiply(a, b) {
return a * b;
}
// Simple test
console.assert(multiply(2, 3) === 6);
console.assert(multiply(2, 3) === 6); // Always same!
// 2. Memoization (caching)
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (key in cache) {
console.log('From cache');
return cache[key];
}
const result = fn(...args);
cache[key] = result;
return result;
};
}
// Only works reliably with pure functions
const memoizedMultiply = memoize(multiply);
console.log(memoizedMultiply(5, 6)); // Computes
console.log(memoizedMultiply(5, 6)); // From cache
// 3. Parallelization (conceptual)
const data = [1, 2, 3, 4, 5, 6, 7, 8];
// Safe to parallelize because pure
const doubled = data.map(n => n * 2);
// BEST PRACTICES
// Do: Keep business logic pure
function calculateDiscount(price, percentage) {
return price * (percentage / 100);
}
// Do: Separate I/O from logic
function processOrder(order) {
const total = calculateTotal(order.items); // Pure
saveToDatabase(total); // Impure, but separated
return total;
}
// Don't: Mix concerns
function badCalculate(price) {
console.log('Calculating...'); // Impure!
const result = price * 0.9;
saveToDatabase(result); // Impure!
return result;
}Practice Sets
This question appears in the following practice sets: