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

# frozen_string_literal: true

Avoid Mutating Methods

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

Lint/Void:
Enabled: true
Lint/CheckForMethodsWithNoSideEffects:
Enabled: true

Prefer Immutable Classes

class BankAccount
attr_reader :balance
def initialize(balance)
@balance = balance
end
def withdraw(amount)
BankAccount.new(@balance - amount)
end
def deposit(amount)
BankAccount.new(@balance + amount)
end
end

Avoid Reassignment

Avoid setters using helpers

Prefer Reusable, Curried Lambdas

2.5.3 :030 > divisible_by = -> (x, y) { (y % x).zero? }.curry
=> #<Proc:0x00007f93671713b0 (lambda)>
2.5.3 :031 > (1..10).select(&divisible_by.(3))
=> [3, 6, 9]

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

foo.rb(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.

Conclusion

  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.

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.

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

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store