Part Nine | Functional Programming Through Elixir: Module Organization vs Class Hierarchies

Where Does Code Live?

In OOP, the answer is always: in a class. Classes are the organizing unit for everything. They hold state, define behavior, inherit from parent classes, and form hierarchies that model relationships between concepts.

In Elixir, the organizing unit is the module. Modules hold functions. That’s it. They don’t hold state, they don’t inherit from other modules, and they don’t form hierarchies. This changes how you think about organizing code.

Read More

Part Eight | Functional Programming Through Elixir: Guards and Pattern Matching in Function Heads

Taking Pattern Matching Further

In Part Four, we introduced pattern matching and saw basic guards in function clauses. We wrote things like when age < 13 and moved on. This post picks up where that left off.

Guards and multi-clause functions are how you structure decision-making in Elixir. Where OOP reaches for if/else chains, switch statements, or the strategy pattern, Elixir uses function heads with guards. Once you’re comfortable with this approach, you’ll find that most conditional logic just becomes more functions.

Read More

Part Seven | Functional Programming Through Elixir: Higher-Order Functions

Beyond Passing Functions Around

In Part Six, we saw how the pipe operator turns nested function calls into readable pipelines. In Part Two, we learned that functions are values. You can pass them to Enum.map and Enum.filter to transform and select data.

Now we’ll go deeper. A higher-order function is a function that does at least one of these things:

  1. Takes a function as an argument (like Enum.map)
  2. Returns a function as its result

You’ve already used higher-order functions when calling Enum.map and Enum.filter. This post covers the most important one you haven’t seen yet, reduce, then gets into writing your own higher-order functions and composing functions together.

Read More

Part Six | Functional Programming Through Elixir: The Pipe Operator

Unreadable Nesting

In Part Five, we saw how recursion replaces loops. Now let’s look at a different readability problem: nested function calls.

Say you need to take a user’s input, trim whitespace, convert it to lowercase, and capitalize the first letter. In Elixir, without the pipe operator, you’d write:

String.capitalize(String.downcase(String.trim("  HELLO WORLD  ")))
# "Hello world"

You have to read this from the inside out. The first operation (trim) is buried in the middle, and the last operation (capitalize) is on the outside. The more steps you add, the worse it gets.

If you’re coming from OOP, you might be used to method chaining, which reads left to right:

# Python - method chaining
"  HELLO WORLD  ".strip().lower().capitalize()
# "Hello world"
// JavaScript - method chaining
"  HELLO WORLD  ".trim().toLowerCase()
// "hello world"
// (JavaScript doesn't have a direct capitalize method)

Method chaining reads nicely, but it only works because each method is attached to the object. In functional programming, functions aren’t bound to objects. They’re standalone. So how do we get the same readability?

Read More

Part Five | Functional Programming Through Elixir: Recursion Over Iteration

A Different Way to Loop

In Part Four, we learned how pattern matching enables elegant data handling. Now we’ll tackle another fundamental shift: in functional programming, you don’t use loops - you use recursion.

If you’re coming from an object-oriented background, loops are probably second nature. for, while, forEach - these are the tools you reach for when you need to process multiple items. But in Elixir, immutability means you can’t have traditional loop counters that increment. Instead, you use recursion: functions that call themselves.

Once you understand recursion, you’ll find it more expressive than loops. It naturally handles complex iteration patterns, and Elixir’s tail-call optimization makes it just as efficient as loops in other languages.

Read More

Part Four | Functional Programming Through Elixir: Pattern Matching

A Different Way to Work with Data

In Part Three, we learned about pure functions and side effects. Now we’ll tackle one of the most distinctive features of functional programming: pattern matching.

Pattern matching is Elixir’s superpower for working with data. It’s not just a fancy way to assign variables - it’s a fundamentally different approach to extracting, validating, and routing data through your program. Once you understand pattern matching, you’ll find conditionals, type checking, and data extraction in OOP languages feel unnecessarily verbose.

Read More

Part Three | Functional Programming Through Elixir: Pure Functions vs Side Effects

The Foundation of Predictable Code

In the first post, we explored immutability. In the second post, we saw how functions are values. Now we’ll tackle a concept that ties them together: pure functions.

Pure functions are the building blocks of functional programming. They’re predictable, testable, and easy to reason about. But real applications need side effects - saving to databases, making HTTP requests, printing to the console. The key is knowing how to write pure functions and where to isolate side effects.

Read More

Part Two | Functional Programming Through Elixir: Functions as First-Class Citizens

Functions Are Values

In the first post, we explored how immutability changes the way we think about data. Now we’ll tackle another fundamental shift: in functional programming, functions are values just like numbers, strings, or lists. You can pass them as arguments, return them from other functions, store them in variables, and put them in data structures.

If you’re coming from object-oriented programming, you’ve probably encountered this concept through callbacks, lambdas, or method references. But in OOP, these often feel like workarounds or special cases. In functional programming languages like Elixir, treating functions as first-class citizens is natural and central to how you write code.

Read More

Part One | Functional Programming Through Elixir: Immutability vs Mutable State

The Foundation of Functional Programming

If you’re coming from an object-oriented programming background, one of the most fundamental shifts in thinking when learning functional programming is immutability. In Elixir and other functional languages, data never changes once it’s created. This might sound limiting at first, but it’s actually a superpower that unlocks predictability, thread safety, and easier debugging.

This is the first post in a series exploring functional programming concepts through Elixir, aimed at developers transitioning from OOP paradigms.

Read More