Constants, globals and scope

Constants and the warning

A name that starts with a capital is a constant: Ruby lets a program assign it once and warns when a second assignment replaces the value. The warning is the feature; the program keeps running with the new value.

ruby -e 'X = 1; X = 2; puts X'

-e:1: warning: already initialized constant X
-e:1: warning: previous definition of X was here
2

The lookup goes outward: a constant written inside a class is looked up in the class, then in the enclosing modules, then at the top level. That is why VERSION inside a gem module finds the constant of the module and not one from another gem with the same name.

The globals Ruby defines

Ruby has a handful of global variables that are always there. The four a script uses:

ruby -e 'puts $PROGRAM_NAME; puts $0 == $PROGRAM_NAME'

-e
true

Write your own globals only in a scratch script. A library that sets $verbose or $debug changes the behaviour of everything that shares the process, and a name collision is impossible to see in a diff.

ENV is not a global

Environment variables look like globals and are not: they live in the process environment and Ruby exposes them through the ENV object, which is a hash-like constant.

ruby -e 'puts ENV.fetch("HOME")'

/home/agent

fetch raises when the variable is missing, which is what a required setting wants. ENV["MODE"] returns nil instead, and ENV.fetch("MODE", "development") gives a default. Lesson 40, later in the course, has the whole configuration lesson.

What to watch for

A constant is not frozen: COLORS = [] can still be pushed to, and every caller sees the change. Freeze the value when it is meant to be read-only, as in lesson 88.

The reassignment warning appears with -w or by default in most setups. Do not silence it with Warning[:deprecated] tricks; a second assignment to a constant is almost always a bug or a rename that missed a line.

Next: Random numbers, ids and tokens

Article author: Arthur Isaev