Submitted by why (Mon Mar 07 03:03:29 UTC 2005)
For many years, users have desired a means of testing for zero, nil and the empty string in a succinct manner. The cases often cited are:
1. The case in which a variable possibly contains a nil or an empty string. The current means of testing for this would be:
if var and var.empty?
Or, more commonly:
2. The case in which a hash contains fields which should be skipped if they contain data (numerical or structural) that is ultimately valueless.
The verbose means of testing for this is to check for the key:
unless hsh.has_key?( 'key' ) and hsh['key'].zero?
The abbreviated form will first ignore nil (the default response for Hash#):
unless hsh['key'] and hsh['key'].zero?
This RCR has a dense history, a portion of which is listed below, based on discussion found on the Ruby-Talk mailing list.
Here are my requirements for a good solution:
Before defending my solution, let me first mention two other worthy answers to this problem.
The first involves creating a Boolean class which can be redefined, at the user's leisure, to include any values which the user wants to test as false.
One implementation of this, offered by Dan Berger, reads:
class Boolean def false nil or "" or 0 end end
This offers the ancillary benefit of giving 'true' and 'false' a mutual father, of which they are the only offspring.
However, this solution violates requirement #1. Users would be forced to choose between two Ruby environments. One of these Ruby environments would test false for 0, nil and "" BUT would break most of the assumptions taught in Ruby tutorials and manuals with concern to regexp matching in particular.
The second solution involves providing a method which casts object to their boolean equivalents. For example, the Integer class could be given a 'to_b' method:
class Integer def to_b zero? end end
Really, this method could be implemented in the same way Object#blank? is implemented below. It would just be named differently.
This solution offers a consistency with other type-casting mechanisms and may be even cleaner than the Object#blank? solution.
Were this to be implemented correctly, I would suggest:
I'm worried about #3 for this change, though. I think it might be a turn off to newcomers.
to_b? What's that? Short for "to boolean."
What's a boolean? Now we're having to introduce too many semantics just to get zero testing as false. And now we have more typecasting litering our code, which is what we're trying to get away from in Ruby.
I believe the concept of Object#blank? is easier to understand. It's simply a more comprehensive test rather than the normal test given by conditionals. A simple word, a simple change.
My only concern with Object#blank? is the possible confusion with String#empty? What's the difference between "blank" and "empty"? But I'd say we just scale back teaching of .empty? and it will settle in that "empty" implies a container, while "blank" implies a value in its most trivial state.
class Object def blank? if respond_to? :empty? empty? elsif respond_to? :zero? zero? else !self end end end
RCRchive copyright © David Alan Black, 2003-2005.
Powered by .