How to Unfreeze an Object in Ruby

How to unfreeze an object in Ruby?

No, according to the documentation for Object#freeze:

There is no way to unfreeze a frozen object.

The frozen state is stored within the object. Calling freeze sets the frozen state and thereby prevents further modification. This includes modifications to the object's frozen state.

Regarding your example, you could assign a new string instead:

script = 'Do you want to build a snowman?'
script.freeze

script = script.dup if script.frozen?
script[/snowman/] = 'castle of ice'
script #=> "Do you want to build a castle of ice?"

Ruby 2.3 introduced String#+@, so you can write +str instead of str.dup if str.frozen?

How to unfreeze the Hash?

Rails (or ActiveSupport if you want to be pedantic) patches a deep_dup method into Hash which does a deep copy. So you should be able to say:

object.to_h.deep_dup

to get a fully mutable version of your Hash.

Frozen objects in Ruby

It means you cannot modify it. You set it by freeze method.

s = "a"

concat modifies the string instance.

s.concat("b")
# => "ab"

When you freeze the string:

s.freeze

then, you cannot apply concat any more.

s.concat("c")
# => RuntimeError: can't modify frozen String

However, you can apply methods that do not modify the receiver:

s + "c"
# => "abc"

What are the ways to override a frozen variable in ruby?

You can get around the issue of unfreezing by just assigning the constant to a new value:

Selenium::WebDriver::Remote::W3C::Bridge.const_set(:COMMANDS, {
upload_file: [:post, 'session/:session_id/file']
}.freeze)

You will get a warning, but it will work.

If you really want to unfreeze, I have to point you to another question on the topic: How to unfreeze an object in Ruby?


in response to comment

The easiest way is to use ActiveSupport Hash#deep_dup from ActiveSupport. If this is a non-rails project, you can add the activesupport gem and require 'active_support/all':

my_commands = Selenium::WebDriver::Remote::W3C::Bridge::COMMANDS.deep_dup

# Here we can change one key only, or do any other manipulation:
my_commands[:upload_file] = [:post, 'session/:session_id/file']
Selenium::WebDriver::Remote::W3C::Bridge.const_set(:COMMANDS, my_commands)

You can also do it without ActiveSupport, but you will need to be a little more careful about how you clone the object because deep_dup is not available, something like this would work instead:

my_commands = Selenium::WebDriver::Remote::W3C::Bridge::COMMANDS.clone.transform_values(&:clone)

And then run the same stuff as in the previous example.

To understand this, read up on the difference between a "shallow" vs "deep" copy of an Object in Ruby, or the difference between "clone" and "deep_dup". Also see Hash#transform_values which I used in that snippet, if you're not familiar with it.

Ruby How we can unfreeze the string using pointer

MRI heap stores RValue struct at that address, first field of that is flags, which has bit FL_FREEZE indicating if the object is frozen - 11th bit in an integer, in x86 bytes go in reverse order, so it can be accessed as 3rd bit of second byte.

The code sets that bit to zero thus 'unfreezing' the object

Freezing associated objects

I worked on an online purchase system before. What you want to do is have an Order class and a LineItem class. LineItems store product details like price, quantity, and maybe some other information you need to keep for records. It's more complicated but it's the only way I know to lock in the details.

An Order is simply made up of LineItems and probably contains shipping and billing addresses. The total price of the Order can be calculated by adding up the LineItems.

Basically, you freeze the data before the person makes the purchase. When they are added to an order, the data is frozen because LineItems duplicate nessacary product information. This way when a product is removed from your system, you can still make sense of old orders.

You may want to look at a rails plugin call 'AASM' (formerly, acts as state machine) to handle the state of an order.

Edit: AASM can be found here http://github.com/rubyist/aasm/tree/master

How to modify elements of Ruby Array composed of Frozen String Literals

Frozen objects can't be unfrozen. But you can build new objects from them.

# frozen_string_literal: true

alphabet = %w(a b c)
alphabet = alphabet.map do |letter|
letter + 'suffix'
end

Ruby freeze method


  • freeze - prevents modification to the Hash (returns the frozen object)
  • [] - accesses a value from the hash
  • stat.class.name.underscore.to_sym - I assume this returns a lowercase, snake case version of the given object's class name (underscore is not in the standard library, so I'm not completely sure)
  • call invokes the lambda associated with stat.class.name.underscore.to_sym key.

For instance, passing ['foo', 'bar'] as the argument to track_for would invoke the send(stat[0], stat[1]) lambda.

Freezing variables in Ruby doesn't work

You freeze objects, not variables, i.e. you can't update a frozen object but you can assign a new object to the same variable. Consider this:

a = [1,2,3]
a.freeze
a << 4
# RuntimeError: can't modify frozen Array

# `b` and `a` references the same frozen object
b = a
b << 4
# RuntimeError: can't modify frozen Array

# You can replace the object referenced by `a` with an unfrozen one
a = [4, 5, 6]
a << 7
# => [4, 5, 6, 7]

As an aside: it is quite useless to freeze Fixnums, since they are immutable objects.



Related Topics



Leave a reply



Submit