Bird
Raised Fist0
Rubyprogramming~15 mins

Pure functions concept in Ruby - Deep Dive

Choose your learning style10 modes available
Overview - Pure functions concept
What is it?
A pure function is a function that always gives the same output when given the same input and does not change anything outside itself. It does not rely on or change any data outside its own scope. This means it has no side effects like changing a global variable or printing to the screen.
Why it matters
Pure functions make programs easier to understand, test, and fix because they behave predictably. Without pure functions, code can become confusing and buggy since functions might change things unexpectedly or give different results each time. This predictability helps developers build reliable software.
Where it fits
Before learning pure functions, you should understand what functions are and how variables work in Ruby. After mastering pure functions, you can learn about functional programming, immutability, and how to write clean, maintainable code.
Mental Model
Core Idea
A pure function is like a simple machine that always produces the same result from the same input without changing anything else.
Think of it like...
Imagine a blender that only blends fruits you put in and never changes the kitchen or the fruits outside. Every time you put the same fruits in, you get the same smoothie, and nothing else in the kitchen is affected.
┌───────────────┐
│   Input Data  │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│  Pure Function│
│ (No side effect)│
└──────┬────────┘
       │
       ▼
┌───────────────┐
│  Output Data  │
└───────────────┘
Build-Up - 6 Steps
1
FoundationUnderstanding Functions in Ruby
🤔
Concept: Learn what a function is and how it works in Ruby.
In Ruby, a function is called a method. It takes inputs called arguments and returns an output. For example: def add(a, b) a + b end puts add(2, 3) # This prints 5
Result
The method add returns 5 when given 2 and 3.
Knowing how methods work is the base for understanding how pure functions behave.
2
FoundationWhat Are Side Effects?
🤔
Concept: Introduce the idea of side effects as changes outside the function.
Side effects happen when a method changes something outside itself, like a global variable or printing to the screen. Example: $x = 10 def change_x $x = 20 end change_x puts $x # Prints 20, the global variable changed
Result
The global variable $x changed from 10 to 20 after calling change_x.
Recognizing side effects helps us see why pure functions avoid them to stay predictable.
3
IntermediateDefining Pure Functions
🤔Before reading on: do you think a function that prints output can be pure? Commit to your answer.
Concept: Pure functions always return the same output for the same input and have no side effects.
A pure function example in Ruby: def multiply(a, b) a * b end puts multiply(3, 4) # Always prints 12 This function does not change anything outside or depend on anything else.
Result
Calling multiply(3, 4) always returns 12 with no side effects.
Understanding purity means knowing that output depends only on input and nothing else changes.
4
IntermediateWhy Avoid Side Effects?
🤔Before reading on: do you think side effects make debugging easier or harder? Commit to your answer.
Concept: Side effects can cause unpredictable behavior and bugs, so avoiding them improves code quality.
If a function changes a global variable or prints inside, it can cause unexpected results elsewhere. Example: $count = 0 def increment $count += 1 end increment increment puts $count # Prints 2 This makes it hard to track changes in $count.
Result
The global variable $count changes each time increment is called, making behavior less predictable.
Knowing side effects cause hidden changes helps us appreciate pure functions' safety.
5
AdvancedPure Functions and Immutability
🤔Before reading on: do you think pure functions can modify objects passed as arguments? Commit to your answer.
Concept: Pure functions do not modify their inputs; they treat data as unchangeable (immutable).
In Ruby, if a method changes an object passed in, it is not pure. Example: def add_element(arr) arr << 5 end my_arr = [1, 2] add_element(my_arr) puts my_arr.inspect # Prints [1, 2, 5], input changed A pure version returns a new array: def add_element_pure(arr) arr + [5] end puts add_element_pure([1, 2]).inspect # Prints [1, 2, 5] This keeps original array unchanged.
Result
Pure functions do not change inputs but return new data instead.
Understanding immutability is key to writing pure functions that avoid hidden bugs.
6
ExpertPure Functions in Real Ruby Code
🤔Before reading on: do you think Ruby's standard library methods are mostly pure or impure? Commit to your answer.
Concept: Ruby methods vary; knowing which are pure helps write better code and use functional patterns.
Many Ruby methods are impure because they modify objects or depend on external state. Example impure method: array.sort! # Changes the array in place Pure alternative: array.sort # Returns a new sorted array Using pure methods helps avoid bugs and makes code easier to test. Ruby developers often combine pure functions with immutable data structures for safer code.
Result
Recognizing purity in Ruby methods guides better programming choices.
Knowing purity in Ruby methods helps you write clearer, more reliable programs and use functional programming techniques effectively.
Under the Hood
Pure functions work by only using their input arguments and returning a result without changing any external data or relying on hidden state. This means the function's output is a direct calculation from inputs, with no side effects like changing variables outside or performing I/O. The Ruby interpreter simply runs the method code and returns the result without affecting anything else.
Why designed this way?
Pure functions were designed to make reasoning about code easier and to avoid bugs caused by hidden changes or unpredictable behavior. Historically, side effects made debugging and testing difficult. Functional programming languages emphasized purity to improve reliability and enable optimizations like caching results. Ruby supports both styles but pure functions help write safer, clearer code.
┌───────────────┐
│   Input Args  │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│  Pure Function│
│  (No side effect)│
└──────┬────────┘
       │
       ▼
┌───────────────┐
│   Output      │
└───────────────┘

(No external state changed or accessed)
Myth Busters - 4 Common Misconceptions
Quick: Does printing inside a function keep it pure? Commit to yes or no.
Common Belief:If a function returns the right output, it is pure even if it prints something.
Tap to reveal reality
Reality:Printing is a side effect, so the function is not pure even if output is correct.
Why it matters:Assuming printing is okay leads to unpredictable behavior and harder testing.
Quick: Can a function that changes a global variable be pure? Commit to yes or no.
Common Belief:Changing global variables inside a function is fine and does not affect purity.
Tap to reveal reality
Reality:Modifying global variables is a side effect, so the function is impure.
Why it matters:Ignoring this causes bugs that are hard to trace because global state changes unexpectedly.
Quick: Does a function that returns different results for the same input count as pure? Commit to yes or no.
Common Belief:A function can be pure even if it sometimes returns different results for the same input.
Tap to reveal reality
Reality:Pure functions must always return the same output for the same input.
Why it matters:Violating this breaks predictability and makes debugging and testing unreliable.
Quick: Are all Ruby methods pure by default? Commit to yes or no.
Common Belief:Most Ruby methods are pure and safe to use in functional style.
Tap to reveal reality
Reality:Many Ruby methods are impure because they modify objects or depend on external state.
Why it matters:Assuming purity can cause unexpected bugs when impure methods change data silently.
Expert Zone
1
Some methods appear pure but internally use caching or memoization, causing hidden side effects.
2
Pure functions enable advanced optimizations like memoization and parallel execution safely.
3
In Ruby, freezing objects helps enforce immutability, supporting pure function design.
When NOT to use
Pure functions are not suitable when you need to perform actions like logging, updating a database, or interacting with the user. In those cases, impure functions or side-effecting code is necessary. Use pure functions for calculations and data transformations, and separate side effects clearly.
Production Patterns
In real Ruby applications, pure functions are used for data processing, calculations, and transformations. Developers combine them with immutable data structures and separate side-effect code (like I/O) to improve testability and maintainability. Functional gems and patterns encourage writing pure methods for safer code.
Connections
Functional Programming
Pure functions are the foundation of functional programming.
Understanding pure functions unlocks the core ideas of functional programming, such as immutability and function composition.
Mathematics - Functions
Pure functions in programming mirror mathematical functions that always produce the same output for the same input.
Seeing programming functions as mathematical functions helps grasp purity and predictability.
Physics - Conservation Laws
Pure functions resemble physical laws that do not change the system but describe consistent relationships.
Recognizing this connection shows how pure functions model stable, predictable systems like natural laws.
Common Pitfalls
#1Changing input data inside a function.
Wrong approach:def add_item(arr) arr << 10 end my_arr = [1, 2] add_item(my_arr) puts my_arr.inspect # Prints [1, 2, 10]
Correct approach:def add_item(arr) arr + [10] end my_arr = [1, 2] new_arr = add_item(my_arr) puts my_arr.inspect # Prints [1, 2] puts new_arr.inspect # Prints [1, 2, 10]
Root cause:Misunderstanding that modifying inputs breaks purity and causes hidden bugs.
#2Printing inside a function to debug or show results.
Wrong approach:def multiply(a, b) puts "Multiplying #{a} and #{b}" a * b end
Correct approach:def multiply(a, b) a * b end puts multiply(3, 4)
Root cause:Confusing side effects like printing with pure computation.
#3Using global variables inside functions.
Wrong approach:$count = 0 def increment $count += 1 end
Correct approach:def increment(count) count + 1 end count = 0 count = increment(count)
Root cause:Not realizing global state changes break function purity and predictability.
Key Takeaways
Pure functions always return the same output for the same input and do not cause side effects.
Avoiding side effects makes code easier to understand, test, and maintain.
Pure functions treat inputs as immutable and do not change them.
Ruby methods vary in purity; knowing which are pure helps write safer code.
Separating pure functions from side-effecting code improves program reliability and clarity.

Practice

(1/5)
1. Which of the following best describes a pure function in Ruby?
easy
A. A function that reads user input and prints output directly.
B. A function that always returns the same output for the same input and has no side effects.
C. A function that modifies global variables to keep track of state.
D. A function that changes the value of its arguments.

Solution

  1. Step 1: Understand pure function definition

    A pure function always returns the same result when given the same input and does not affect anything outside itself.
  2. Step 2: Compare options to definition

    A function that always returns the same output for the same input and has no side effects. matches this definition exactly. Options A, B, and D involve side effects or changing external state.
  3. Final Answer:

    A function that always returns the same output for the same input and has no side effects. -> Option B
  4. Quick Check:

    Pure function = consistent output + no side effects [OK]
Hint: Pure functions never change outside data and always return same output [OK]
Common Mistakes:
  • Thinking functions that modify variables are pure
  • Confusing input/output consistency with side effects
  • Assuming printing output is allowed in pure functions
2. Which Ruby function below is a pure function?
easy
A. def add(a, b); a + b; end
B. def add(a, b); puts a + b; end
C. def add(a, b); @sum = a + b; end
D. def add(a, b); print a + b; end

Solution

  1. Step 1: Check each function for side effects and output consistency

    def add(a, b); a + b; end returns sum without changing anything outside or printing. def add(a, b); puts a + b; end prints (side effect). def add(a, b); @sum = a + b; end changes instance variable (side effect). def add(a, b); print a + b; end prints (side effect).
  2. Step 2: Identify pure function

    Only def add(a, b); a + b; end meets pure function rules: same output for same input, no side effects.
  3. Final Answer:

    def add(a, b); a + b; end -> Option A
  4. Quick Check:

    Pure function = no side effects + returns value [OK]
Hint: Pure functions return values without printing or changing variables [OK]
Common Mistakes:
  • Confusing printing output with returning value
  • Assuming modifying instance variables is allowed
  • Assuming print doesn't cause side effects
3. What is the output of this Ruby code?
def multiply(x, y)
  x * y
end

result = multiply(3, 4)
puts result
medium
A. Error
B. nil
C. 12
D. 7

Solution

  1. Step 1: Understand the multiply function

    The function returns the product of x and y, so multiply(3, 4) returns 12.
  2. Step 2: Check the output statement

    puts prints the returned value, so it prints 12.
  3. Final Answer:

    12 -> Option C
  4. Quick Check:

    multiply(3,4) = 12 [OK]
Hint: Pure functions return predictable output; multiply(3,4) = 12 [OK]
Common Mistakes:
  • Thinking function returns nil if no explicit return
  • Confusing addition with multiplication
  • Expecting error due to missing return keyword
4. Identify the error in this Ruby function that is supposed to be pure:
def increment(n)
  n += 1
  puts n
end
medium
A. It modifies the input variable n.
B. It uses invalid syntax for increment.
C. It does not return any value explicitly.
D. It prints output, causing a side effect.

Solution

  1. Step 1: Check for side effects

    The function prints the value of n, which is a side effect because it affects outside world.
  2. Step 2: Verify other aspects

    Modifying n locally is allowed; syntax is correct; implicit return is allowed but printing breaks purity.
  3. Final Answer:

    It prints output, causing a side effect. -> Option D
  4. Quick Check:

    Pure functions must not print or cause side effects [OK]
Hint: Printing inside function breaks purity due to side effects [OK]
Common Mistakes:
  • Thinking local variable change breaks purity
  • Assuming implicit return is an error
  • Ignoring side effects caused by printing
5. You want to write a pure function in Ruby that takes a list of numbers and returns a new list with each number doubled. Which implementation is pure?
hard
A. def double_list(nums) nums.map { |n| n * 2 } end
B. def double_list(nums) nums.collect! { |n| n *= 2 } nums end
C. def double_list(nums) nums.map! { |n| n * 2 } end
D. def double_list(nums) nums.clear nums.push(2, 4, 6) end

Solution

  1. Step 1: Understand pure function requirements

    A pure function returns new data without changing input or external state.
  2. Step 2: Analyze each option

    def double_list(nums) nums.collect! { |n| n *= 2 } nums end uses collect! which modifies original array (side effect). def double_list(nums) nums.map { |n| n * 2 } end returns a new array with doubled values without changing original. def double_list(nums) nums.map! { |n| n * 2 } end uses map! which modifies original array (side effect). def double_list(nums) nums.clear nums.push(2, 4, 6) end clears and modifies original array (side effect).
  3. Final Answer:

    def double_list(nums) nums.map { |n| n * 2 } end -> Option A
  4. Quick Check:

    Pure function = no input change + returns new data [OK]
Hint: Use non-destructive methods like map, avoid modifying input [OK]
Common Mistakes:
  • Using destructive methods like map! or clear
  • Modifying input array instead of returning new one
  • Confusing each with map for transformation
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard