Please stop using ||= all the time
Tags: ruby, refactoring, readability
Published: 2022-04-18 18:17:08

---
title: Please stop using ||= all the time
published: true
description: Don't use the ||= operator when a regular intialize assignment will do
tags: ruby, refactoring, readability
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y72miw3x9g44lyebkgmv.jpeg
---

In ruby code I often see people writing code like

```ruby
def foo
	@foo ||= 'bla bla bla'
end
```

Instead of

```ruby
def initialize
	@foo = 'bla bla bla'
end

attr_reader :foo
```

The duck operator `||=`  is used to lazily initialize the instance variable, instead of initializing the instance variable in the `initialize` method.

This is possible in ruby because assignments are also expressions, and all methods have an implicit return value. So `@foo ||= 123` always evaluates to `123` but never assigns to `@foo` more than once.

While this is very concise, I found it odd when I first came to ruby after coding in other languages. It feels like a very roundabout way of doing things. If you are initializing instance variables why not use the initializer?

The lazy initialization pattern is one way to avoid running an expensive computation that might not be needed. However, if you know that the initialization is always going to be required for the object to be usable, then there are no performance benefits to structuring it this way.

Structuring code like this makes dependencies a bit harder to notice just from looking at the class. Users of the class might be misled into thinking that the object is fully initialized when it is not, and this can make it harder to initialize objects in a test or in other parts of the codebase.

In practice, I get suspicious even when the initialization *is* optional, because the optional initialization is still separate from the initializer and so it is less obvious when reading the code. Optional behaviour can also be sign that the class has [more than one responsibility](https://en.wikipedia.org/wiki/Single_responsibility_principle).

You can always refactor the class to avoid this. For example, consider using [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) to depend on the result of the computation instead of doing the computation internally.

```ruby
def initialize(foo: nil)
	@foo = foo
end

# ...
# methods that use `foo`
# ...

private

attr_reader :foo
```

Lazy initialization is a special case of [temporal coupling](https://www.pluralsight.com/tech-blog/forms-of-temporal-coupling_): the behaviour of the class is allowed to vary depending on what order you call its methods in. The more complex the behaviour, the harder it is to reason about the code and the easier it is to introduce bugs. In this case, if other methods of your class depend on the instance variable, then they could read `nil` if the initializer method isn't called first.

Side note: I see this problem a lot with rails controllers, which do not get initialized on a per-request basis, and force you to set instance variables within your action methods as a way to communicate with the view. This design is unfortunate, but you can still avoid the problem elsewhere in your codebase.

On the other hand, if all the initialization for the class is handled by the `initialize` method, it's quite easy to make the behaviour of the class predictable. You can use [command-query responsibility segregation](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation) (CQRS) to ensure that messages you send to the object either ask for information, or change the objects state, but not both.

[Photo by Francesco Altamura from Pexels](https://www.pexels.com/photo/brown-and-white-duck-on-water-7745377/)