Use `nil` when you mean it

08 Oct 2014

Null pointer (sometimes written NULL), used in computer programming for an uninitialized, undefined, empty, or meaningless value (More).

null is meaningless. Yet, how many times have you seen implementations like this?

if !accounts.nil?
  accounts.each do |account|
    account.do_something
  end
end

If accounts had been an empty collection ([]) we could run the above block without the nil check.

accounts.each do |account|
  account.do_something
end

That’s because a Collection object is prepared to respond to the :each message, even when it's empty. Your objects, too, should know how to respond to the messages passed.

For example:

type = nil
output = OutputDevice.find_by_type(type)
output.print "This shouldn’t print anywhere"

If our OutputDevice implementation returned nil when it doesn’t find an appropriate output device based on type, we’d get an error for trying to pass it the :print message, because it simply doesn't know how to respond to it. This would force us to add a nil check.

output.print "Without the nil check, this breaks" unless output.nil?

Remember the purpose of nil is to represent the concept of meaningless or empty.

Null […], used in computer programming for an uninitialized, undefined, empty, or meaningless value.

If we instead return a NilOutputDevice object (for example) that responds to :print appropriately, our code is much better and resistant to change.

class NilOutputDevice
  def print(message)
    # do nothing, discard message
  end
end

type = nil
output = OutputDevice.find_by_type(type)
output.print "This shouldn’t print anywhere"

In this simple example it makes more sense to just remove the print statement if we don’t want to print anything, but you can imagine how functionality like this might be desirable, e.g. when you’re writing a module inside a bigger system, and want to redirect the output to monitors, printers, or even hide it completely.