Rick DeNatale wrote:
mortee wrote:
Well, if you’d like it so much, why not just redefine it in your own
programs? Everyone else seems to expect it to return 0 instead of being
hostile by throwing an exception…
In fact, I’m almost ready to go out on the limb and suggest that it
might be nice if: [NilClass implemented +, -, *, /]
[…]
which would allow sequences like:
a ||= 0
a += 1
To be just
a += 1
As I said ALMOST ready to go out on a limb, since I haven’t spent much
time pondering the consequences.
This is just an example of how easy it is to do the Null Object
Refactoring in Ruby. Another nice one is
class NilClass; def []; nil end end
which allows things like @potentially_nil[1][:foo][:bar] to return nil
instead of throwing a NoMethodError.
I must admit that I don’t really understand the OPs position. My
interpretation is as follows:
(1) nil is not false, but, when used in a Boolean context,
one can generally reasonably interpret nil to be
somewhat similar to false, without screwing up Boolean
semantics too much.
(2) nil is not 0, but, when used in a numerical context,
one can generally reasonably interpret nil to be
somewhat similar to 0, without screwing up numerical
semantics too much.
To me, (1) and (2) are exactly the same, but for some reason the OP
seems to be perfectly comfortable with (1) but violently opposed to
(2), and I don’t understand what the difference is.
The whole point of having a full fledged nil object like in Ruby or
Smalltalk (or Haskell), as opposed to some null pointer like in C,
C++, C# or Java, is, that my program doesn’t blow up if I’m dealing
with a nil. In C, NULL is invalid. In Java, null is invalid, it isn’t
even an object, it doesn’t really exist. When I try to evaluate null
in a Boolean context in Java, I don’t get false like I would in Ruby,
I get a NullPointerException and my program terminates. In C,
accessing a NULL pointer will generally not even gracefully terminate
but simply crash the program. That is precisely what a full fledged
nil object avoids, so, to me, it makes perfect sense that said object
can be reasonably used in a variety of contexts, without crashing or
throwing exceptions.
That is not to say, that nil.to_i returning 0 is always right! I do
believe however, that nil.to_i throwing an exception is almost always
wrong and that returning 0 is generally right. If, however, I want to
multiply a series of values, some of which might be nil, it would make
sense to redefine nil.to_i to return 1 (because it is the neutral
element of multiplication) instead of 0 and/or additionally
(re)defining nil.* to return its argument. Similarly for to_s: in a
report generator, it might make sense to redefine nil.to_s to return
“N/A” instead of the empty string, in a HTML table generator to return
" ", in a debugger to return “nil” and so on. Sometimes it might
even make sense to define method_missing to always return nil and
never throw a NoMethodError.
Heck, in some twisted situation it might even be desirable to be able
to make nil evaluate to true in a boolean context (after all, true
is the neutral element of conjunction), althought that is
unfortunately not possible in Ruby.
I hope that makes some sense and explains why it might be desirable
and sensible to be able to send messages to nil, convert nil to other
types and use nil in different contexts without having to worry about
exceptions or crashes.
jwm