I’m currently working on a new rails 5 API project. All response codes and response descriptions are predefined. I need to put them in namespaced constants so I can easily refer them in the code and in tests.

This is the interface I envisioned initially:

# some_controller.rb
def some_action
  # ...
  data = {
    code: RESPONSE::SUCCESS[:code]
    description: RESPONSE::SUCCESS[:description]
  }
  render json: data
end

The RESPONSE constant is just a container for other hash constants:

module RESPONSE
  SUCCESS = {code: '1111', description: 'success'}
  INVALID_AUTH_TOKEN = {code: '1112', description: 'invalid authtoken'}
  # ...
end

Immediately I desired a more object-oriented way of accessing the data. RESPONSE::SUCCESS.code is much better than RESPONSE::SUCCESS[:code].

module RESPONSE
  SUCCESS = OpenStruct.new code: '1111', description: 'success'
  INVALID_AUTH_TOKEN = OpenStruct.new code: '1112', description: 'invalid authtoken'
  # ...
end

I get to type 2 chars less for each line. And I get to live longer by.. maybe a few hours?

But then a nagging feeling: I’m replacing a simple hash with a heavier OpenStruct object. In the worst case where there are huge numbers of response codes, will there be a memory problem?

ObjectSpace::memsize_of came to help me clarify things. You just take an object and give it to it, and it will return its size in bytes.

…and so hash vs openstruct:

require 'ostruct'
require 'objspace'

hash = {a: 'aa', b: 'bb'}
os = OpenStruct.new a: 'aa', b: 'bb'

Object.memsize_of hash
# 232

Object.memsize_of os
# 40

6x smaller!

Indeed! OpenStruct objects are much smaller because they don’t have all the bells and whistles a Hash object has.

So I had accidentally stumbled upon a better way. Is there an even better way?

RC = Struct.new :a, :b
struct = RC.new 'aa', 'bb'
ObjectSpace.memsize_of struct
# 40

Struct and OpenStruct are better than hash.

What about BasicObject?

class RC < BasicObject
  attr_reader :a, :b
  def initialize a, b
    @a = a
    @b = b
  end
end

bo = RC.new 'aa', 'bb'
bo.a   # 'aa'
bo.b   # 'bb'

ObjectSpace.memsize_of bo
# 40

Same as Struct and OpenStruct. So can’t get any better than these? Please share if you have any ideas.