DEV Community

Cover image for Ruby constants
David Boureau
David Boureau

Posted on • Originally published at bootrails.com

Ruby constants

article originally published here : https://www.bootrails.com/blog/ruby-constants/

Motivation

We don't have a lot of Ruby constants in the bootrAils starter. However, it's always good to know how they work when the need arises.

"Constants" are variables that are not meant to be changed. Let's see how. In this article we will use the ruby console, if you are in a Rails environment, you can get it by typing bin/rails console.

How to define a Ruby constant

Constants begin with an uppercase letter.

Example :

Boiling = 100 # valid
BOILING = 100 # valid
boiling = 100 # invalid
Enter fullscreen mode Exit fullscreen mode

Constants defined within a class or module can be directly accessed from the inside. Those defined outside a class or module can still be accessed globally.

Example :

class Water
   ICE = 0
   BOIL = 100
   def show
      puts "Celsius temperature for becoming ice is #{ICE}"
      puts "Celsius temperature for becoming steam is #{BOIL}"
   end
end
Enter fullscreen mode Exit fullscreen mode

As you can notice, ICE and BOIL are freely accessed from the class where they are defined. From the outside :

Water::ICE
# => 0
Water::BOIL
# => 100
Water.new.show
# => Celsius temperature for becoming ice is 0
# => Celsius temperature for becoming steam is 100
Enter fullscreen mode Exit fullscreen mode

Ruby constants that will fail

Constants cannot be defined inside a method.

Example :

class Water
   def show
      ICE = 0
      BOIL = 100
      puts "Celsius temperature for becoming ice is #{ICE}"
      puts "Celsius temperature for becoming steam is #{BOIL}"
   end
end
# Traceback (most recent call last):
# SyntaxError ((irb):117: dynamic constant assignment)
# ICE = 0
Enter fullscreen mode Exit fullscreen mode

Constants cannot start with a lower case.

class Water
   ice = 0 # ! fail ! Constant cannot start with lowercase
   boil = 100 # ! fail ! Constant cannot start with lowercase
   def show
      puts "Celsius temperature for becoming ice is #{ice}"
      puts "Celsius temperature for becoming steam is #{boil}"
   end
end
Enter fullscreen mode Exit fullscreen mode

This will produce the following error on call :

Water::ice
Traceback (most recent call last):
        1: from (irb):87:in `<main>'
NoMethodError (undefined method `ice' for Water:Class)
Enter fullscreen mode Exit fullscreen mode

Uninitialized Constant Error

This kind of error will often happen if you code with Ruby-on-Rails or any other framework. It often means a class or constant inside a module wasn't found. You can easily recreate this error on your computer :

class Water
   ICE = 0
   BOIL = 100
   def show
      puts "Celsius temperature for becoming ice is #{ICE}"
      puts "Celsius temperature for becoming steam is #{BOIL}"
   end
end
Enter fullscreen mode Exit fullscreen mode

And then try simply to access a constant that doesn't exists :

irb(main):131:0> Water::ICE
0
irb(main):132:0> Water::UNEXISTING
Traceback (most recent call last):
        1: from (irb):132:in `<main>'
NameError (uninitialized constant Water::UNEXISTING)
Enter fullscreen mode Exit fullscreen mode

Changing... A Ruby constant

This is something disturbing if you come from another language : Ruby constants can be changed without the raise of any error.

Water::ICE = 42
# => warning: already initialized constant Water::ICE
Water::ICE
# => 42
Enter fullscreen mode Exit fullscreen mode

A warning is raised, but the program still continues.

If you want to avoid this default behaviour, you have to freeze your constant.

For this example, I'm going to freeze... the ice.

class Water
   ICE = 0.freeze
   BOIL = 100.freeze
   def show
      puts "Celsius temperature for becoming ice is #{ICE}"
      puts "Celsius temperature for becoming steam is #{BOIL}"
   end
end
Enter fullscreen mode Exit fullscreen mode

It doesn't really work, because you can still make Water::ICE = 42 and have a simple warning.

A Ruby constant isn't actually immutable, and you can't freeze a variable.

See this excellent StackOverflow answer to circumvent this problem : https://stackoverflow.com/a/26542453/2595513

Discussion (0)