In Progress
Unit 1, Lesson 1
In Progress

Keyword Argument Struct

The Struct class-generator has been an important part of the Ruby toolkit since early days. But in Ruby 2.5 it got modernized. Learn how to combine the convenience of Structs with the readability of keyword arguments!

Video transcript & code

We've talked about structs in the past


Room = Struct.new(:name, :north, :south, :east, :west)

pantry = Room.new("pantry")
dining = Room.new("dining room")
kitchen = Room.new("kitchen", nil, pantry, nil, dining)
pantry.north = kitchen
dining.east = kitchen

  • Episode #20
  • Good for a quick data-centric class
  • I use them for placeholders a lot

Historically they require positional constructor arguments

Room = Struct.new(:name, :north, :south, :east, :west)

Positional has drawbacks

  • Hard to remember order
  • Have to fill in nil for unspecified attributes
kitchen = Room.new("kitchen", nil, pantry, nil, dining)

It would be nice if we could use keyword args

By default it doesn't have the effect we expect

kitchen = Room.new(name: "kitchen", south: pantry, west: dining)

And we can!

Since Ruby 2.5. But we have to do it for ALL args.

Room = Struct.new(:name, :north, :south, :east, :west, keyword_init: true)
# ...
pantry = Room.new(name: "pantry")
dining = Room.new(name: "dining room")
kitchen = Room.new(name: "kitchen", south: pantry, west: dining)

It even works with the shorthand constructor

pantry = Room[name: "pantry"]
dining = Room[name: "dining room"]
kitchen = Room[name: "kitchen", south: pantry, west: dining]

There are some trade-offs

No positional args:

kitchen = Room["kitchen", nil, pantry, nil, dining]
# ~> error

But structs have a new lease on life with keyword constructors!

Room = Struct.new(:name, :north, :south, :east, :west, keyword_init: true)

pantry = Room[name: "pantry"]
dining = Room[name: "dining room"]
kitchen = Room[name: "kitchen", south: pantry, west: dining]
pantry.north = kitchen
dining.east = kitchen

Responses