The Ruby Craftsman

Freeze Ruby Constants [Video]
An intro video to Ruby constants their enforcement pitfalls and how to fix them and why you should care in your code.
In computer programming, a constant is a value that cannot be altered by the program during normal execution, i.e., the value is constant. - Wikipedia
This is what happens in Ruby when redefining a constant with another object.
A_CONST = :first_value
A_CONST = :new_value
It outputs a warning.
warning: already initialized constant A_CONST
If you’re not paying attention to warnings in Ruby then enforcing constants is not possible. I would recommend that you listen to this warning and fix them when they come up.
If the constant is attempted to be reassigned dynamically for example with a method this is not just a warning, but a syntax error.
def hello
A_CONST = 2
end
SyntaxError: dynamic constant assignment
A_CONST = 2
^
It can still be done dynamically it just needs different syntax, but this will also produce a runtime warning.
Object.const_set(:A_CONST, 3)
warning: already initialized constant A_CONST
warning: previous definition of A_CONST was here
When Warnings Are Not Enough
COMPANY_OWNER = "Dustin Zeisler"
What happens when some code is written while not paying attention and does a destructive action on the String?
COMPANY_OWNER.gsub!("i", "")
#=> "Dustn Zesler"
COMPANY_OWNER
#=> "Dustn Zesler"
The String object is still technically the same object, so no Ruby warnings will happen. This does not meet the expectation of what a constant value should be. Is there anything that we can do about it? Glad you asked this is where #freeze
comes in.
COMPANY_OWNER = "Dustin Zeisler".freeze
COMPANY_OWNER.frozen?
#=> true
COMPANY_OWNER.gsub!("i", "")
RuntimeError: can't modify frozen String
If this is not a common mistake you feel you are going to make it also has performance improvements, see www.sitepoint.com/unraveling-string-key-performance-ruby-2-2.
Note: Alternative for String#freeze
With the release of Ruby 2.3, strings can be frozen by default without the use of #freeze. By adding the following magic comment at the top of a file all string literals will default to frozen.
# frozen_string_literal: true
Other common mutable objects in Ruby are Hash and Array. If these objects are being set as a constant I would recommend also freezing them.
There is no built-in way to unfreeze an object, but if you really want to here is a StackOverflow post on how to do it.
If you like this sort of thing subscribe to get new posts delivered directly to your inbox.