This content originally appeared on DEV Community and was authored by Kelly Popko
In practice, a main difference between instances of Data and Struct is mutability:
- Instances of Data are immutable*
- Instances of Struct are mutable
*Mutable values passed to instances of Data remain immutable by default.
Data also has fewer (and different) 'built-in' methods than Struct.
This post explores differences in syntax and behavior between Data and Struct.
Syntax comparison: Create New Instance
Data
House = Data.define(:rooms, :area, :floors)
ranch = House.new(rooms: 5, area: 1200, floors: 1)
# => #<data House rooms=5, area=1200, floors=1>
Struct
House = Struct.new(:rooms, :area, :floors, keyword_init: true)
ranch = House.new(rooms: 5, area: 1200, floors: 1)
# => #<struct House rooms=5, area=1200, floors=1>
Mutability: Attempt to Renovate the house...
Data
House = Data.define(:rooms, :area, :floors)
ranch = House.new(rooms: 5, area: 1200, floors: 1)
# => #<data House rooms=5, area=1200, floors=1>
ranch.floors = 2
# (irb):3:in `<main>': undefined method `floors=' for an instance of House (NoMethodError)
This tells us there is no 'writer' (sometimes called "setter" in other
languages) method to use.
If we try to define a writer method on House
and update that value, FrozenError
is raised.
House = Data.define(:rooms, :area, :floors) do
def floors=(quantity)
@floors = quantity
end
end
# => House
cottage = House.new(rooms: 5, area: 700, floors: 1)
# => #<data House rooms=5, area=700, floors=1>
cottage.floors = 2
# (irb):21:in `floors=': can't modify frozen House: #<data House rooms=5, area=700, floors=1> (FrozenError)
cottage.frozen?
# => true
What we can do with a Data object is clone it and update any of the attribute values.
House = Data.define(:rooms, :area, :floors)
cottage = House.new(rooms: 5, area: 1200, floors: 1)
# => #<data House rooms=5, area=1200, floors=1>
two_story_cottage = cottage.with(floors: 2)
# => #<data House rooms=5, area=1200, floors=2>
Struct
With Struct, we can renovate.
House = Struct.new(:rooms, :area, :floors, keyword_init: true)
ranch = House.new(rooms: 5, area: 1200, floors: 1)
# => #<struct House rooms=5, area=1200, floors=1>
ranch.floors = 2
# => 2
ranch
# => #<struct House rooms=5, area=1200, floors=2>
ranch.frozen?
# => false
Built-in Methods
Data Class
>> Data.methods(false)
=> [:define]
>> Data.instance_methods(false)
=>
[:deconstruct_keys,
:pretty_print,
:pretty_print_cycle,
:deconstruct,
:hash,
:==,
:inspect,
:members,
:to_s,
:with,
:eql?,
:to_h]
Struct
>> Struct.methods(false)
=> [:new]
>> Struct.instance_methods(false)
=>
[:deconstruct_keys,
:==,
:members,
:to_a,
:to_s,
:[],
:[]=,
:values_at,
:eql?,
:to_h,
:select,
:filter,
:pretty_print,
:pretty_print_cycle,
:deconstruct,
:hash,
:inspect,
:each_pair,
:values,
:length,
:dig,
:size,
:each]
Comparison
>> struct_methods - data_methods
=>
[:to_a,
:[],
:[]=,
:values_at,
:select,
:filter,
:each_pair,
:values,
:length,
:dig,
:size,
:each]
>> data_methods - struct_methods
=> [:with]
This content originally appeared on DEV Community and was authored by Kelly Popko

Kelly Popko | Sciencx (2025-08-09T19:58:15+00:00) Ruby Data Class vs Struct. Retrieved from https://www.scien.cx/2025/08/09/ruby-data-class-vs-struct/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.