Something's been bothering me lately. It's
nothing, really. ?, ?,
null,
nil, or whatever you want to call it. I think we've got it backwards in many cases. Many languages like to throw errors when you try to use
nothing as if it were something else - even if it's nothing fancy.
I think a better default behavior would be to
do nothing - at most log an error somewhere, or allow us a setting - just stop acting as if the world came to an end because I *gasp* tried to use
null as if it were a normal value.
In fact, just because it's nothing, doesn't mean it can't be something. It
is something - a concept at the minimum. And there's nothing stopping us from having an object that represents the concept of
nothing.
Exceptions should be thrown when something exceptional happens. Maybe encountering a null value was at some time, exceptional. But in today's world of databases, form fields, and integrated disparate systems, you don't know where your data is at or where it's coming from - and encountering
null is the rule, not the exception.
Expecting me to write
paranoid code and add a check for
null to avoid every branch of code where it might occur is ludicrous. There's no reason some sensible default behavior can't be chosen for
null, and if I really need something exceptional to happen, I can check for it.
Really, aren't you sick of writing code like this:
string default = "";
if(form["field"] != null and boolFromDBSaysSetIt != null
and boolFromDBSaysSetIt)
default = form["field"];
when you could be writing code like this:
if(boolFromDBSaysSetIt)
default = form["field"];
I think this is especially horrid for conditional checks. When I write
if(someCase) it's really just shorthand for
if(someCase eq true). So why, when
someCase is
null or not a
boolean should it cause an error? It's not
true, so move on - don't throw an error.
Someone tell me I'm wrong. It
feels like I should be wrong. But it feels worse to have the default path always be the one of
most resistance.
What do you think?
Hey! Why don't you make your life easier and subscribe to the full post
or short blurb RSS feed? I'm so confident you'll love my smelly pasta plate
wisdom that I'm offering a no-strings-attached, lifetime money back guarantee!
Leave a comment
I completely disagree with this. NULL is meant to be an exceptional value, that's the reason it exists. That is it's default behavior.
I would argue that if you are finding it a problem, then the databases you're dealing with, or the code that acquires the data should be modified to handle the problem. NULL isn't a data value, it's an exception to data, so why should it be stored in a database? DBs can refuse null values, so if your column is marked not null, you have a reasonable assumption that you don't have to check it.
I don't think the problem is so much that null causes defensive code, I think the problem is that people have become desensitized to null values. They are exceptional, they do indicate problems (such as uninitialized values) and shouldn't be used for every day occurances.
The default case for your conditional, you answer your own question. If someCase is NOT A BOOLEAN, how can it be evaluated in a boolean expression? That would then raise the question, why can't I use "if (Blah)". Which would beg the question, how does Blah translate to true/false? Equally, how does null translate to true/false?
Consider if you had something like this (C++):
class Cat {
operator bool () const { return false; }
}
...
if (!someCat) {...
Is there a cat? or is there not a cat?
So.. can you imagine how insane debugging code like that could be when a null value slips through and null defaulted to false or true?
I want null exceptions, they make tracking down bugs easier. :)
Posted by
Glitch
on Apr 09, 2008 at 04:45 PM UTC - 5 hrs
Oh, and for my example above in C++..
C++ considers NULL to be 0. In C++/CLI nullptr gets the same treatment. So, converting the example above (since boolean operator would need dereferencing in C++ due to using pointers not references) to C++/CLI gives the functionality you're kind of suggesting.
Cat ^someCat = nullptr;
if (!someCat) // evaluates to true
someCat = gcnew Cat();
if (!someCat) // evaluates to true.
So, in reality.. null still needs to be accounted for.
Posted by
Glitch
on Apr 09, 2008 at 04:59 PM UTC - 5 hrs
You can use null most places in SQL where you'd use non-null values, but it almost always does something subtly weird. It's not equal to false, or zero, or an empty string, and it's not even equal to null. This makes sense to me, but I'm not sure that in a 3GL I'd prefer it to just dealing with exceptions. I definitely don't want nulls to start pretending they aren't nulls unless I explicitly ask them to.
On another level, if you have an object the null object pattern is a great way to deal with this - you can independently define null semantics for each class hierarchy. It's just a sad fact that nearly all our OO languages go all procedural on us at some point, beyond which we're back to writing != null.
Posted by Jaime Metcher
on Apr 09, 2008 at 09:44 PM UTC - 5 hrs
> I want null exceptions, they make tracking down bugs easier.
I considered that - which is why I mentioned the bit about having a setting somewhere.
Re: null evaluating as false in boolean expressions, it can certainly happen - Both Javascript and Ruby (that I know of off the top of my head) consider null to be false.
In C and C++, as you mention null is 0 - and 0 evaluates to false IIRC.
I guess what I really want is for Java and C# (and ColdFusion, specifically for booleans) to have a different concept of NULL than they do. In CF, there is no null really - if you try to access a hash with a key that doesn't exist, it does throw an error. But if you get null from the DB it's just a blank string. This is irritating when you want to decide what to do based on a column that could be null.
But it's retarded in .NET, for example, if an Active Directory object does not have a value for a field, it's null. So, for every field before I do anything with it, I actually have to check to see if exists in that particular AD object.
I just think nulls are so common, that maybe they need a new construct or they should have thought about using null a bit harder depending on what is going on.
Jaime - I see what you're getting at- I wouldn't like that either. So, maybe I really want something else - but I'm having trouble finding words for it. I hope I can eventually do better than what I tried above. =)
The truth is there are cases where I care *a lot* about if an object is null, and there are cases where I don't care. Because of how prolific nulls are in everything, there spots I don't care far outnumber those where I do.
Posted by
Sammy Larbi
on Apr 10, 2008 at 04:19 PM UTC - 5 hrs
It kind of seems most of your dislikes are steming from the APIs and technologies external to the actual languages.
For instance, Active Directory. The reason most properties return null is because many of the default schema properties are MayContain properties. Which mean the object doesn't have to have those properties. So, if the object doesn't have the property, it only makes sense to return null (like any other property that isn't on the object). MustContain properties will always return the value they've been initialized with (and the object can't be created without initializing MustContain properties).
Likewise, a good database API (i hesitate to say like ADO.NET), provides wrapper objects like DataRow which contain methods to test for null columns. Even perl's db library returns undef for null columns.
I personally don't think any of these are the fault of the language. Unless the language specifically does something wrong (like evaluating null to ""), I don't see any reason to change the language for the faults of the APIs.
One thing to look at though, if the .NET libraries are truley frustrating, is extension methods for C# 3.0. You can write an extension method for say, Object that allows you to IsNull any object (even null references, since it is a compiler trick and not a real instance method). You could even implement a new method for specific classes to provide you with the default values you wanted.
Posted by
Glitch
on Apr 10, 2008 at 05:17 PM UTC - 5 hrs
As far as my understanding of Ruby, nil (or null) values are instances of the NilClass. This allows you to call instance methods such as .nil? on a nil value or adding custom methods to handle unhandled methods using method_missing if you really want to.
Posted by mike
on May 23, 2008 at 01:29 AM UTC - 5 hrs
I'm not a big fan of Groovy, but its safe navigation 'operator' (doesn't seem like an operator to me) sounds intriguing. (
http://groovy.codehaus.org/Operators#Operators-Saf...%28%3F.%29 )
The idea is that you can write "?." instead of "." when traversing into object members and act as if everything was always null - if any part of the traversal becomes null, the whole expression turns into null. To wit: quux = foo?.bar?.baz will set quux to null if either of foo, bar or baz are null.
I like C#'s only null-is-special trick, foo ?? bar, where bar will be used in place of null in case foo contains that.
Posted by
Jesper
on Jun 25, 2008 at 03:56 PM UTC - 5 hrs
@Jesper - Thanks for sharing that. I didn't know about ?. in groovy, but it sure does sound useful. It can be a pain to check if each intermediate object is null before getting to the one you really want.
Maybe that's the answer I'm looking for.
Posted by
Sammy Larbi
on Jun 26, 2008 at 07:20 AM UTC - 5 hrs
Leave a comment