Symbols

Dear Computer

Chapter 2: Naming Things

Symbols

Variables are always a pairing of two things: a name and value. Could you imagine a situation where you wanted just a name without an associated value? Consider this snippet of Ruby that updates an xy-position according to the direction an entity is facing:

ruby
if direction == 1
  y += 1
elsif direction == 2
  x += 1
elsif direction == 3
  y -= 1
else
  x -= 1
end

The problem with this code is that the direction numbers have no inherent meaning. Developers must remember that 1 means north, 2 means east, 3 means south, and 4 means west. Meaning can be restored by using strings as flags instead of numbers:

ruby
if direction == 'north'
  y += 1
elsif direction == 'east'
  x += 1
elsif direction == 'south'
  y -= 1
else
  x -= 1
end

This reduces the cognitive burden, but it has an impact on performance. Strings are more expensive to compare than integers.

A few languages provide a feature for introducing meaningful names that have no meaningful value and that can be compared quickly—in constant time. These are symbols. In Ruby, a symbol literal is an identifier preceded by a colon. This code is both readable and fast:

ruby
if direction == :north
  y += 1
elsif direction == :east
  x += 1
elsif direction == :south
  y -= 1
else
  x -= 1
end

The first time the Ruby interpreter encounters a particular symbol, it assigns the symbol a unique integer and stores or interns the association in a global dictionary. Any later references to that symbol in any scope will look up the symbol in the dictionary and evaluate to that same integer.

The particular integer assigned to a symbol is unimportant beyond its uniqueness. But Ruby does let you inspect the integer with the object_id method.

Symbols are supported in several other languages, including Lisp and JavaScript. A similar effect can be achieved in C, C++, and Java using enums.

← Naming PracticesReassignment and Mutability →