Struct vs Data in Ruby 3.2
In the world of Ruby programming, the Struct
and Data
classes are both used to create simple data objects. This article takes an in-depth approach to understanding the similarities, differences, and optimal usage strategies of these classes in Ruby.
Understanding Struct and Data Classes
Before we delve deeper, let's understand the basic concept of these classes.Struct
is a built-in Ruby class that allows you to define simple data structures. It's mutable, meaning that you can change the values after initializing it.Data
, on the other hand, arrived with Ruby 3.2 and is essentially a Struct
but without writer methods. This means that once it's created, it's immutable. You can't change the values because it doesn't have a setter method. This class must be used with Data.define
. Let's see it in action.
Using Data
# Data is basically a struct with no writer methods
# basic usage of the default Data.define from Ruby 3.2
Project = Data.define(:title, :description)
project = Project.new("Example", "Example description")
puts project.title
# => "Example"
project.title = 'abcd' # it will raise error because it's immutable
In the code snippet above, we define a data class Project
with two attributes, title
and description
. We then instantiate it and print the title
, which works fine. But when we try to change the title
, it throws an error because it is immutable.
Extending the Data class
We can create a new class that extends Data.define
and add methods to it as required.
class Project < Data.define(:title, :description)
def cover
"#{title} #{description}"
end
end
# we can use keyword arguments
project = Project.new(description: "Example description", title: "Title")
puts project.cover
# => "Title Example description"
In the new class Project
, we have added a cover method that outputs the title
and description
.
Understanding Struct Class
Like we mentioned before, a Struct
is mutable. Let's see a demonstration.
# data vs struct - the main difference is that the struct is mutable, so we can change values after initialization
ProjectStruct = Struct.new(:title, :description)
project = ProjectStruct.new("Example", "Example description")
puts project.title
# => "Example"
project.title = 'aa'
puts project.title
# => "aa"
Here we initialized ProjectStruct
with Example
, but we could later change it to aa
.
Benchmarking Data vs. Struct vs OpenStruct
From the performance analysis and benchmarking between the Data
, Struct
and OpenStruct
classes, it appears that Data
and Struct
are quite similar in terms of performance, with OpenStruct
lagging behind as it is considerably slower(based on https://github.com/lucianghinda/value-object-in-ruby-benchmarks). In my opinion, OpenStruct
should be deprecated.
Summary
The introduction of the Data
class to the Ruby language brought with it the ability to define immutable data structures, very similar to structs, but without the ability to mutate data once it's set. When deciding whether to use Struct
or Data
, it really comes down to whether you need your objects to be mutable or immutable.
understand
Happy coding!