
True, False And Nil Objects In Ruby - askorkin
http://www.skorks.com/2009/09/true-false-and-nil-objects-in-ruby/
======
stcredzero
It's a bad idea to put methods on nil willy-nilly. I see stuff like this in
Smalltalk projects all the time. People like to put < and > on nil and think
they're clever because they fixed their little routine that does a sort. What
they don't realize, is that they've possibly broken something else that
depends on the Does Not Understand exception as part of its normal operation.
(Yes, remember there's only _one_ nil object, and you have no comprehensive
list of what implicit contracts it has to fulfill in the rest of the code
base. Certain proxy mechanisms can break. I know of another mechanism in one
Smalltalk's streams that would break as well.)

The correct way to replace your nil checks with polymorphism is with the
MissingObject pattern. Languages with explicit types should give you this for
free. I think that even duck-typed languages should do this. (Every time you
define a class Foo, you get MissingFoo automatically.) They can often be
provided by libraries.

~~~
jerf
Another option that I'm really warming to is to put it right in the type
system whether or not you might have "Nulls". You can sort [Int] and you can
sort [Maybe Int] if you provide the correct sort functions, but either way,
there's no surprises. There simply will not be a "null" in an [Int].

While I'm using Haskell's notation, it seems likely that pretty much any
strongly typed language could do something like this, at least ad hoc. (That
is, Haskell hasn't actually written this into the typing system, it's just a
direct use of the type system that it already had. But even a C++-like
language could probably put this in there if it was written that way from day
one; arguably, it's allowing the nulls to exist in the first place that is
actually the hack.)

~~~
masklinn
> it seems likely that pretty much any strongly typed language could do
> something like this

No. Or more precisely, in a dynamically typed language (which may or may not
be strongly typed) there's no point in doing so, it won't buy you anything
expressivity or correctness over nullable references.

Pretty much any _statically_ typed language would benefit from making
names/references non-nullable by default and moving nullability into the type
system yes.

> it's allowing the nulls to exist in the first place that is actually the
> hack

How is it a hack? It's trivial to implement, but there's nothing hacky about
it.

~~~
jerf
Type system hack, not code hack. Certainly the implementation is trivial, yes.
Even under the weaker type systems of C++ or Java, having this magical,
undeclared value that is _also_ a Circle and a Car and an Account and so on is
pretty dirty from the type point of view.

Haskell of course has its own troubles with bottom, and I note some people
think we should be doing away with that, too.

~~~
masklinn
> Type system hack, not code hack.

It's not either. Types are simply implicitly defined as nullable, as they are
in SQL.

~~~
jerf
And I call that a hack, especially when I don't think it was done on purpose
or with thought, but simply because "that's how it needs to work". The fact
that it wasn't intended as a hack doesn't make it not a hack; I'm sure that by
2050 we'll be looking back on types that could be magically NULL in much the
same way I currently curse at SQL every time something generates "SELECT *
FROM blah WHERE value IN ()". ("Damn it, SQL, it's just an empty list and
always false, what's the damn big deal?! So very 70s...") There's a whole slew
of things like that from older technologies; someday I really ought to make a
list.

------
KevinMS
Rails does what he mentions ...

    
    
      [shell] ./script/console
      Loading development environment (Rails 2.3.3)
      >> nil.blank?
      => true
      >> "".blank?
      => true
      >> [].blank?
      => true
      >> {}.blank?
      => true
    

It lets you write cleaner code in situations when you don't care if an object
is empty data or a nil. Avoiding the "whiney nils" ruby has a reputation for.

instead of

if myobj && myobj.size == 0 then :blah end

you can write

if myobj.blank? then :blah end

makes me miss perl though

------
ianbishop
> Now if your code is playing with objects that quack like a duck and you end
> up with a nil instead of a DuckLike object, your nil object will be able to
> quack a sensible default value (or raise an error if you prefer).

I never knew this but it will definitely come in handy.

~~~
bhousel
Because NilObject is actually an object, it is possible to add some methods
that take some of the pain out of dealing with maybe-nil objects..

My favorite is the andand gem:
<http://github.com/raganwald/andand/tree/master>

It lets you turn code like this..

    
    
       entry.at('description') && entry.at('description').inner_text
    

..into code like this..

    
    
       entry.at('description').andand.inner_text

~~~
masklinn
Why not stick to EAFP and go with something along the lines of:

    
    
        begin entry.at('description').index_text
        rescue NoMethodError; end
    
    ?

~~~
raganwald
What happens when you write:

    
    
        begin
          entry.at('description').indx_txt
        rescue NoMethodError
        end
    

? With the generic rescue you will always get nil back. With #andand you get
nil from nil and a NoMethodError from objects, which is usually what you want.

Also, if #index_text is correctly spelled but _it_ raises a NoMethodError,
you're silently discarding it again. For this reason, I avoid silently
discarding exceptions even when I think I know what I'm doing. If I'm wrong,
I'm in a lot of trouble...

------
KevinMS
Didn't read, too wide!

