Embracing Functional Style in Ruby

Driven by Code
Sep 9, 2019 · 3 min read

By: Noah Matisoff

The benefits of functional programming have become well-known and battle-tested, especially in recent years, and are being adopted in languages that aren’t touted as functional programming languages.

Specifically, in Ruby, there have been many great articles and talks on how to adopt functional style, and even how to mix it with object-oriented programming. Some insightful articles can be found below that will help with prefacing the rest of this article:

  1. Functional Programming in Ruby — Brandon Weaver
  2. Functional Programming in Ruby for people who don’t know what functional programming is — Amber Wilkie
  3. Avoid Mutation — Functional Style in Ruby — Tom Dalling

… and many more!

The standard library even tends to default to methods that are functional over mutating, though does support mutating methods with the bang notation(mapvs. map! , for example). Below, I have outlined conventions, standards, and a styleguide for embracing functional style in your existing applications.

Adopting the Style

String Immutability

By default, strings are mutable in Ruby. This tended to result in lots of calls to Object#freeze on String objects. However, as of Ruby 2.3, a magic comment can be added to all files to make strings immutable:

Avoid Mutating Methods

Avoid mutating methods where possible, and adopt a preference for map, reduce, each_with_object, etc. Additionally, treat methods with a bang ( ! ) as a code smell, and carefully consider trade-offs.

This can be adopted by adding the following rules via Rubocop:

Prefer Immutable Classes

Rather than mutating internal state in an object, adopt a preference for creating a new object with any would-be modified state. The classic example is a bank account object that exposes public APIs for withdraw(amount) and deposit(amount) . Rather than taking this approach, consider the below:

  def initialize(balance)
@balance = balance
def withdraw(amount)
BankAccount.new(@balance - amount)
def deposit(amount)
BankAccount.new(@balance + amount)

Avoid Reassignment

Reassigning any variables in your program is likely a smell that it’s imperative style and not using functional methods where it could be. Ruby does not have final variables (like Java) or const variables (like JavaScript), so be mindful of any reassignments and carefully weigh the trade-offs.

Avoid setters using helpers

As convenient as attr_writer and attr_accessor are, they’re exposing public APIs for mutating internal state in objects. attr_reader is still acceptable, but any “setter” methods should avoid mutating internal member variables.

Prefer Reusable, Curried Lambdas

Prefer reusable lambdas over defining logic and conditions manually. For example:

As opposed to rewriting the same Enumerable#select with different arguments in each case in your codebase:

(1..10).select { |num| (num % 3).zero? }bar.rb(1..10).select { |num| (num % 5).zero? }

These are simple examples, but can be applied to any realistic data processing, filtering, or mapping to your domain or context.


Adopting and embracing functional style in Ruby can empower the developer, but more importantly:

  1. Typically is less error prone.
  2. Makes it easier to grok data flow and onboard developers.
  3. Avoids mixture of non-functional and functional style in your Ruby projects.

So next time you’re writing in Ruby, consider the trade-offs of functional style and make conscious decisions while enjoying the expression and options that are available in this great language!

Driven by Code

Technology is our art. We learn so much from the community and we want to give back. This is our contribution.

Driven by Code

Written by

Welcome to TrueCar’s technology blog, where we write about the interesting things we‘re working on. Read, engage, and come work with us!

Driven by Code

Technology is our art. We learn so much from the community and we want to give back. This is our contribution.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade