Zero, Blank, and Nil
Back in the bad old days of web development, I used JSP to create page content. Java is a terribly language for doing front-end web work, because it’s bad at processing text, and which usually comprises the majority of what web apps do. (And that’s also why Perl was the reigning king in this realm for so long.)
One of the things that drove me absolutely batty about JSP was the need to check every string for both null and blank, which meant your code was littered with stuff like:
if (request.get("quantity") != null && request.get("quantity") != "")
{
quantity = (int)request.get("quantity")
doSomething(quantity);
}
Yikes. When I moved on to PHP, I was immediately struck by the improved readability of the same code:
if (strlen($quantity) > 0)
doSomething($quantity);
An empty string and a null will both give you zero on a string length. (You can always use === or isset() if you want to check for null explicitly.) A similar guard clause if often used for integers and arrays, too. In Java you have to check both whether a value is null, and whether it is zero or empty, respectively. In PHP you can just do:
if ($quantity != 0)
and
if (!empty($array))
Now that I’m living in Ruby land, I’ve found that my code is generally much prettier than PHP for most things… except this one. Ruby is a bit more strongly typed that PHP, so I’m back to the JSP syntax:
if params[:value] != nil and !params[:value].empty?
Hardly the succinct readability one has come to expect.
Ruby’s base classes provide some nice convenience functions to make your code more readable: Array.empty?, String.blank?, and Fixnum.zero?. The solution here seems obvious: make all of these methods exist on NilClass.
Thanks to Ruby’s metaprogramming, it’s easy to add this to your own application:
class NilClass
def empty?; true; end
def blank?; true; end
def zero?; true; end
end
Great! Now we can just do:
if params[:value].empty?
Furthermore, I would tend to think that all of these should be collapsed together into a single method. I think empty? is the most applicable. So empty? means a blank string, a zero, or an empty array or hash. This reflects what the code really wants to know: is there anything in this variable? Should I bother doing anything with it? 95% of the time, the difference between nil and non-nil but empty is irrelevant.
Update: aidanf suggests using .blank? instead, which I like a bit better than the names suggested above.
Update 2: A coworker informed me that Rails extends most of the basic Ruby types with blank?. So you can do [].blank?, {}.blank?, nil.blank?, 5.blank?, etc. Apparently this is pretty unknown, because not one person mentioned it in the many dozens of comments on this post appearing on various news aggregators. Note that 0.blank? does return false, but in most cases I’m more interesting in strings anyway.
November 22nd, 2006 at 10:28 pm
Nice that Ruby’s metaprogramming can be made to emulate Python’s default behaviour.
November 22nd, 2006 at 11:46 pm
The example below is not quite as concise as the php example, but it’s clearer, and not any less efficient.
if quantity.to_s.empty? > 0
If it’s nil, it converts to ” instantly. If it’s already a string, to_s just returns the exact same object that was passed to it.
I don’t want ruby to let me say anything convoluted like 5.empty?
November 22nd, 2006 at 11:47 pm
s/empty/blank/g
November 23rd, 2006 at 3:01 am
if params[:value].to_s != ”
will do the trick nicely. nil.to_s returns an empty string.
November 23rd, 2006 at 6:35 am
This code fails:
class NilClass
def empty? { true }
def blank? { true }
def zero? { true }
end
The reason is the incorrect method definition syntax. It should look like this:
class NilClass
def empty?
true
end # etc ..
end
# or even
class NilClass
%w(empty? blank? zero?).each { |m| define_method(m) {true} }
end
Also, there was a ruby-talk thread about this some time ago, and the general conclusion was that this was bad form, since asking if nil is ‘empty?’ doesn’t make sense. nil is nothing. Does it make sense to ask if nothing is empty? Or if 42 is blue? And so on…
November 23rd, 2006 at 6:45 am
Well, there are actually several more elegant ways to do your initial try than the horrible Java-style condition you used here:
NILness should not be tested with “!= nil”, there are two idioms to test “nilness”:
> the nil? predicate method, available on every object, it returns “true” if and only if the object is an instance of NilClass
> “nil” is the only non-boolean object in Ruby which coerces to a boolean “false” (everything else, including empty strings and the integer “0″ compute to true)
This means that your test could be translated to one of those:
if params[:value] and !params[value].empty?
if not (params[:value].nil? or params[:value].empty?)
November 23rd, 2006 at 9:46 am
Which version of Ruby are you using?
class NilClass
def empty?; true; end
def blank?; true; end
def zero?; true; end
end
November 23rd, 2006 at 9:55 am
Doesn’t the rails method blank? already have this behaviour?
> ruby script/console
Loading development environment.
>> nil.blank?
=> true
>> "".blank?
=> true
>> [].blank?
=> true
>> {}.blank?
=> true
November 23rd, 2006 at 8:35 pm
My initial thought was to add empty? and blank? to NilClass - but adding zero? ? I’m not sure about that it seems too much like polluting the concept of nil - the first two additions (esp empty?) seem to fit better.
An alternative that came to mind was to do something like:
if (params[:value] || ”).empty?
…
which has the nice property of using params[:value] if it is not nil and using an explicit empty string if it is. This simple bit of code ensures we can always call empty? (provided that params[:value].responds_to? :empty when it is not
nil).
And numerically:
if (maybe_something || 0).zero?
…
These sort of possibilities convinced me quite a while ago that forcing “boolean” expressions to a strict true or false value is not necessarily a good thing for anything but training wheels.
November 24th, 2006 at 1:11 pm
Personally, I prefer PHP’s
if ($quantity)
and even
if ($array)
November 27th, 2006 at 3:35 pm
If in understand correctly It looks like why’s object.blank? acheives the same
http://redhanded.hobix.com/inspect/objectBlank.html
giving code like:
if params[:value].blank?
December 1st, 2006 at 7:52 pm
I usually use ‘x.to_s.empty?’, ‘x.to_i.zero?’ or ‘x.to_a.empty?’ rather than adding methods to NilClass. The effect is the same, and it doesn’t surprise other coders.
This is a pretty common complaint for Perl/PHP coders going to a more strongly typed language, but if you’re used to having a strong typing system, then ‘((”" == 0) - 1 == ())’ evaluating to true in Perl can be maddening.
December 7th, 2006 at 9:22 am
.blank? does what you’re looking for already. It returns true for nil objects, and empty (or white-space-only) strings.
See for the bug against the docs.
September 2nd, 2007 at 10:17 am
[…] That’s useful, but I had either never read it, or had read it and forgotten it. Apparently I’m not the only one. […]