I prefer that functions throw an exception when unable to do what they promised, rather than return nil or a null object. The try-catch block serves as documentation that the function might fail. If someone forgets to catch the exception, it will shut everything down rather than leave the program in an unanticipated state that could lead to an error elsewhere.
Scala's standard library provides very helpful information on how to replace null with its Maybe class (called Option in Scala). Just take a peek into their collections library[4], and search for Option.
[1] http://www.infoq.com/presentations/Null-References-The-Billi...
[2] http://moonbase.rydia.net/mental/writings/programming/monads...
[3] http://andand.rubyforge.org/
[4] http://www.scala-lang.org/api/current/scala/collection/immut...
Do you have a source for this? I was under the impression nil was directly taken from Smalltalk, which derived it from Lisp.
def nil.method_missing(*args, &block); end
So now you can call nil.whatever.you.like and get nil. It's also still falsy, but now every nil value in your app silently works and doesn't throw an error.It's both impressive and scary that Ruby lets you (or that new contractor you're not sure about) change the fundamentals of the language in one line of code.
https://github.com/raganwald/homoiconic/blob/master/2009-02-...
In Objective-C nil will absorb any messages too, see the section "Sending Messages to nil" in http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/...
As a application creator, is is only bad when/if you open source part of it. Otherwise, you can always run the gems' tests against the compillation of your env.
if finished?
do_something
end
then finished? is not expected, and may not, return nil.If you expect some_value to be able to be nil (which, for boolean values, is hardly ever), you should write
if !some_value.nil? && some_value
do_something
end
In the end, these 'convenient' coercions that allow you to use any value as a boolean only come back to bite you, because unexpected stuff happens when stuff is unexpectedly nil. If it makes my coworkers cry that an object is nil and true at the same time, then they are at fault, not me.Edit: and more importantly (I forgot to point this out explicitly) a non-nil value != true. That any string or integer is 'true' can lead to very hard-to-find bugs.
if some_value
do_something
end
It's a core expectation of the language that !!nil_thing == false, so why violate it? if !some_value
do_something
end
you often don't actually want it to be executed when some_value is nil instead of false. And when it is, you go scratching your head and searching where some_value came from, to discover some silly typo.In some ways, the reverse is even worse: when you write
if some_value
do_something
end
and you change some_value from nil to some sensible default like '', you will forget to update this clause and you will not understand why the code is being executed. If you use if !some_value.nil?
do_something
end
you don't have that problem, because the nil-test sticks out like a sore thumb.This could lead to a tri-state ifs (with true/false/nil branches).
Or you can just consider that 2-branch 'if' runs the first branch if the test expr is true and the second 'otherwise'. (So that doesn't make nil false, it just makes it non-true).
And then your interpretation and everyone else co-exists and we can all code together.
What stuff should happen when something is unexpectedly nil if you tested it for truth-ishnes? Once you have written
if not some_value
something with some_value
end
the only things you can do with `x` are things you can do with `false`, which are not many. if some_value
something with some_value
end
where you first use nil to signal false, but later change the base case of some_value from nil to 0, nil to NullObject or nil to some other base value. Since you think of these base cases as 'nothing', you will forget to change this related conditional the first time around, because it seems it would still do the right thing.I know the reasoning (it's much faster to do math on object IDs than it is to call a method), but there are workarounds for this (e.g. only allowing frozen objects to be boolean-false, and having the object's truth-ness/false-ness represented by the return value of its #false? method at the time of freezing—thus allowing the interpreter to locate it in a semantically-meaningful part of object-ID space that can later be masked for in a TEST instruction.)
For example (and there are code smells in this, but it gets the idea across):
if account = Account.create(params[:account])
...
else
complainAbout account.errors
end
Truthiness should not be reserved for whether an object exists, it could also be used for whether it is valid, complete, or anything else.My particular example might not be a great one, but I think framework and library developers ought to be able to work a consistent use for truthiness and falseness into their creations, e.g. a true object has been saved, a true object is valid, a true object is complete, a true object represents the current state of the world instead of the past or future or a wrong state, and so forth.