๐ŸŽ“ A1Learner
๐Ÿ”
0 of 28 lessons completed

Ruby Freeze Lifecycle

Freezing an object and then trying to change it raises an error. This lesson follows that error and the limits of what a freeze covers.

Changing a frozen string fails

The string freezes on the second line, so the append on the third line raises FrozenError. The stated output is the first line of that real error.

word = "abc"
word.freeze
word << "d"
puts word

freeze is shallow

The outer array is frozen, but its first inner array is not. Appending to the inner array works, and its length grows to three.

rows = [[1, 2], [3, 4]]
rows.freeze
rows[0] << 9
puts rows[0].length
puts rows.frozen?
puts rows[0].frozen?

Freezing inside initialize

Seal freezes itself at the end of initialize. Every finished seal is frozen from the moment it exists.

class Seal
  def initialize(text)
    @text = text
    freeze
  end
  def text
    @text
  end
end
seal = Seal.new("approved")
puts seal.frozen?
puts seal.text

Frozen hash values stay mutable

The hash is frozen, yet the array stored as one of its values is a separate object. That array still grows, and it reports itself unfrozen.

settings = { labels: ["a"] }
settings.freeze
settings[:labels] << "b"
puts settings[:labels].length
puts settings.frozen?
puts settings[:labels].frozen?

Example

class Packet
  def initialize(items)
    @items = items
    freeze
  end
  def items
    @items
  end
end
packet = Packet.new([1, 2])
puts packet.frozen?
packet.items << 3
puts packet.items.length
puts packet.items.frozen?

Key points

  • Appending to a frozen string raises FrozenError.
  • freeze is shallow and locks only the outer object.
  • An inner array inside a frozen array can still grow.
  • Freezing inside initialize makes each finished object frozen.
  • The values stored in a frozen hash stay mutable.
  • A frozen object keeps answering reads after the freeze.

In this example, Packet freezes itself inside initialize, so the finished packet reports frozen. The items array inside it was never frozen, so it still grows to three items. The freeze covered the packet, not the objects it holds.

Note

Shallow means nested objects need their own freeze to lock.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

Why can an array inside a frozen array still grow?