TIL that Ruby, or to be more precise Class class, offers allocate public instance method. According to the documentation the method:

Allocates space for a new object of class’s class and does not call initialize on the new instance. The returned object must be an instance of class.

The same documentation includes a nice code snippet explaining the above description:

klass = Class.new do def initialize(*args) @initialized = true end def initialized? @initialized || false end end klass.allocate.initialized? #=> false klass.new.initialized? #=> true

To learn even more about it, you can check its tests in the official Ruby repository.

Thanks to digging into Ruby source code ( of the Class.new method to be precise) I learned even more. klass = Class.new do def self.allocate raise "allocate should not be called" end end 2.5.3 :047 > klass.new => #<#<Class:0x00007fbd5a05c340>:0x00007fbd5a03f678> tests file of themethod to be precise If I overwrote `allocate` method in any of my classes, `new` one would still call the original `allocate` defined in Class class. What a surprise 🙂

What are allocate responsibilities?

Classes in Ruby are first-class objects, each is an instance of Class class. To create a new object of a concrete class we usually call new method which is also defined within Class class. What does the new do?

It calls the allocate first to allocate required space in the memory and assign the result to obj variable. Invokes initialize method on the obj passing to them all the arguments. Returns obj object.

We can translate the above points into some piece of code:

class Class def new(*args) obj = allocate obj.initalize(*args) obj end end

What value does allocate provide for us?

Simply speaking, it gives a freedom to define custom object initializers. Speaking more technically, it gives us more control over object creation. Let’s consider a simple example:

class User def initialize @details = {} end end

A common way to make it possible to set `@details` hash is extending the intialize method itself:

class User def initialize(details = {}) @details = details end

The other possible solution is to use `allocate` method inside a custom class public method:

class User def self.initialize_with_age(age) obj = allocate obj.instance_variable_set(:@details, { age: age }) obj end end

An example usage:

2.5.3 :020 > user = User.new => #<User:0x00007fbd5a02fd90 @details={}> 2.5.3 :022 > user_with_age = User.initialize_with_age(15) => #<User:0x00007fbd590f3660 @details={:age=>18}>

Doesn’t allocate add unnecessary magic to Ruby?