Changing the Way Ruby Creates Objects
Tags: ruby, learning
Published: 2018-08-07 13:12:14

---
title: Changing the Way Ruby Creates Objects
layout: layout_ruby_magic
description: In this edition of Ruby Magic, we'll look at how Ruby creates and initializes objects and how we can modify the default behavior.
tags: ruby, learning
cover_image: https://blog.appsignal.com/images/blog/2018-08/rm-objects.jpg
published: true
canonical_url: https://blog.appsignal.com/2018/08/07/ruby-magic-changing-the-way-ruby-creates-objects.html
---

One of the things that makes Ruby great is that we can customize almost anything to our needs. This is both useful and dangerous. It's easy to shoot ourselves in the foot, but when used carefully, this can result in pretty powerful solutions.

At Ruby Magic, we think useful and dangerous is an excellent combination. Let's look at how Ruby creates and initializes objects and how we can modify the default behavior.

## The Basics of Creating New Objects from Classes

To get started, let's see how to create objects in Ruby. To create a new *object* (or *instance*), we call `new` on the class. Unlike other languages, `new` isn't a keyword of the language itself, but a method that gets called just like any other.

```ruby
class Dog
end

object = Dog.new
```

In order to customize the newly created object, it is possible to pass arguments to the `new` method. Whatever is passed as arguments, will get passed to the initializer.

```ruby
class Dog
  def initialize(name)
    @name = name
  end
end

object = Dog.new('Good boy')
```

Again, unlike other languages, the initializer in Ruby is also just a method instead of some special syntax or keyword.

With that in mind, shouldn't it be possible to mess around with those methods, just like it is possible with any other Ruby method? Of course it is!

## Modifying the Behavior of a Single Object

Let's say we want to ensure that all objects of a particular class will always print log statements, even if the method is overridden in subclasses. One way to do this is to add a module to the object's singleton class.

```ruby
module Logging
  def make_noise
    puts "Started making noise"
    super
    puts "Finished making noise"
  end
end

class Bird
  def make_noise
    puts "Chirp, chirp!"
  end
end

object = Bird.new
object.singleton_class.include(Logging)
object.make_noise
# Started making noise
# Chirp, chirp!
# Finished making noise
```

In this example, a `Bird` object is created using `Bird.new`, and the `Logging` module is included in the resulting object using its singleton class.

> __What's a Singleton Class?__
> Ruby allows methods that are unique to a single object. To support this, Ruby adds an anonymous class between the object and its actual class. When methods are called, the ones defined on the singleton class get precedence over the methods in the actual class. These singleton classes are unique to every object, so adding methods to them doesn't affect any other objects of the actual class. <a href="https://ruby-doc.com/docs/ProgrammingRuby/html/classes.html">Learn more about classes and objects in the Programming Ruby guide.</a>

It's a bit cumbersome to modify the singleton class of each object whenever it is created. So let's move the inclusion of the `Logging` class to the initializer to add it for every created object.

```ruby
module Logging
  def make_noise
    puts "Started making noise"
    super
    puts "Finished making noise"
  end
end

class Bird
  def initialize
    singleton_class.include(Logging)
  end

  def make_noise
    puts "Chirp, chirp!"
  end
end

object = Bird.new
object.make_noise
# Started making noise
# Chirp, chirp!
# Finished making noise
```

While this works well, if we create a subclass of `Bird`, like `Duck`, its initializer needs to call `super` to retain the `Logging` behavior. While one can argue that it's always a good idea to properly call `super` whenever a method is overridden, let's try to find a way that doesn't *require* it.

If we don't call `super` from the subclass, we lose the inclusion of the `Logger` class:

```ruby
class Duck < Bird
  def initialize(name)
    @name = name
  end

  def make_noise
    puts "#{@name}: Quack, quack!"
  end
end

object = Duck.new('Felix')
object.make_noise
# Felix: Quack, quack!
```

Instead, Let's override `Bird.new`. As mentioned before, `new` is just a method implemented on classes. So we can override it, call super, and modify the newly created object to our needs.

```ruby
class Bird
  def self.new(*arguments, &block)
    instance = super
    instance.singleton_class.include(Logging)
    instance
  end
end

object = Duck.new('Felix')
object.make_noise
# Started making noise
# Felix: Quack, quack!
# Finished making noise
```

But, what happens when we call `make_noise` in the initializer? Unfortunately, because the singleton class doesn't include the `Logging` module yet, we won't get the desired output.

Luckily, there's a solution: It's possible to create the default `.new` behavior from scratch by calling `allocate`.

```ruby
class Bird
  def self.new(*arguments, &block)
    instance = allocate
    instance.singleton_class.include(Logging)
    instance.send(:initialize, *arguments, &block)
    instance
  end
end
```

Calling `allocate` returns a new, uninitialized object of the class. So afterward, we can include the additional behavior and only then, call the `initialize` method on that object. (Because `initialize` is private by default, we have to resort to using `send` for this).


> __The Truth About <code>Class#allocate</code>__
> Unlike other methods, it's not possible to override <code>allocate</code>. Ruby doesn't use the conventional way of dispatching methods for <code>allocate</code> internally. As a result, just overriding <code>allocate</code> without also overriding <code>new</code> doesn't work. However, if we're calling <code>allocate</code> directly, Ruby will call the redefined method. <a href="https://ruby-doc.org/core-2.5.0/Class.html#method-i-allocate">Learn more about <code>Class#new</code> and <code>Class#allocate</code> in Ruby's documentation.</a>

## Why Would We Do This?

As with a lot of things, modifying the way Ruby creates objects from classes can be dangerous and things might break in unexpected ways.

Nonetheless, there are valid use cases for changing the object creation. For instance, ActiveRecord uses `allocate` with a different `init_from_db` method to change the initialization process when creating objects from the database as opposed to building unsaved objects. It also uses `allocate` to convert records between different [single-table inheritance](https://en.wikipedia.org/wiki/Single_Table_Inheritance) types with `becomes`.

Most important, by playing around with object creation, you get a deeper insight into how it works in Ruby and open your mind to different solutions. We hope you enjoyed the article.

We'd love to hear about the things you implemented by changing Ruby's default way of creating objects. Please don't hesitate to leave a comment.

_[Benedikt Deicke](http://benediktdeicke.com) is a software engineer and CTO of [Userlist.io](http://userlist.io). On the side, he's writing a book about building [SaaS applications in Ruby on Rails](http://saasguidebook.com). You can reach out to Benedikt via [Twitter](http://twitter.com/benediktdeicke)._