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.