Proper way to use the Struct

We use Structs in Ruby to create simple classes with constructor and some instance variables.

Look at this simple User class:

{% highlight ruby %} class User attr_accessor :first_name, :last_name, :age

def initialize(first_name, last_name, age) @first_name = first_name @last_name = last_name @age = age end end {% endhighlight %}

Using Struct, you can simply use a single line instead of declaring attr_accessors and constructor and the class will have exactly the same API:

{% highlight ruby %} User = Struct.new(:first_name, :last_name, :age) {% endhighlight %}

But when it comes to a class with internal resources like constants, you may get a warning:

{% highlight ruby %} User = Struct.new(:first_name, :last_name, :age) do MIN_AGE = 18

some methods dealing with user

end

Admin = Struct.new(:first_name, :last_name, :age) do MIN_AGE = 21 end

=> warning: already initialized constant MIN_AGE

=> warning: previous definition of MIN_AGE was here

{% endhighlight %}

What happends here? We assumed that MIN_AGE was declared inside User and Admin, but actually it was declared on the top level:

{% highlight ruby %}

Object::MIN_AGE => 18 {% endhighlight %}

And warnings were printed.

But wait, there is actually a proper way to subclass from Struct:

{% highlight ruby %} class User < Struct.new(:first_name, :last_name, :age) LIMIT = 1 end

class Admin < Struct.new(:first_name, :last_name, :age) MIN_AGE = 21 end {% endhighlight %}

No warnings here!

I also recommend you to check it the post by Steve Klabnik, where he describes all power of Struct.

Written in October 2015.
Kir Shatrov

Kir Shatrov helps businesses to grow by scaling the infrastructure. He writes about software, scalability and the ecosystem. Follow him on Twitter to get the latest updates.