views:

279

answers:

9

I know that NULL isn't necessary in a programming language, and I recently made the decision not to include NULL in my programming language. Declaration is done by initialization, so it is impossible to have an uninitialized variable. My hope is that this will eliminate the NullPointerException in favor of more meaningful exceptions or simply not having certain kinds of bugs.

Of course, since the language is implemented in C, there will be NULLs used under the covers.

My question is, besides using NULL as an error flag (this is handled with exceptions) or as an endpoint for data structures such as linked lists and binary trees (this is handled with discriminated unions) are there any other use-cases for NULL for which I should have a solution? Are there any really important implications of not having NULL which could cause me problems?

+7  A: 

There's a recent article referenced on LtU by Tony Hoare titled Null References: The Billion Dollar Mistake which describes a method to allow the presence of NULLs in a programming language, but also eliminates the risk of referencing such a NULL reference. It seems so simple yet it's such a powerful idea.

Update: here's a link to the actual paper that I read, which talks about the implementation in Eiffel: http://docs.eiffel.com/book/papers/void-safety-how-eiffel-removes-null-pointer-dereferencing

Greg Hewgill
I read that article on λtU but I misunderstood its meaning originally. Thanks for correcting me on that. I'll read up on how Eiffel does this.
Imagist
+1  A: 
Tim
I don't pass things back by reference; everything is pass-by-const-reference. However, I'd be interested to understand what the code above does. I've never coded Objective-C before so I don't know what's going on in that code. Would you be willing to give a brief explanation?
Imagist
Sure. Basically, errors in Objective-C that don't warrant exceptions are represented by instances of the NSError object. A lot of methods may fail during their execution, but not necessarily; what they do in this case is add a by-reference argument that is an NSError object, so to figure out the error the programmer creates one of those objects and passes it by reference to the method. If the method encounters a problem, it puts the details in the object and the programmer is responsible for handling it later. If the programmer doesn't care about the error, though, they can pass in nil.
Tim
A: 

In my mind there are two uses cases for which NULL is generally used:

  • The variable in question doesn't have a value (Nothing)
  • We don't know the value of the variable in question (Unknown)

Both of common occurrences and, honestly, using NULL for both can cause confusion.

Worth noting is that some languages that don't support NULL do support the nothing of Nothing/Unknown. Haskell, for instance, supports "Maybe ", which can contain either a value of or Nothing. Thus, commands can return (and accept) a type that they know will always have a value, or they can return/accept "Maybe " to indicate that there may not be a value.

RHSeeger
Javascript makes this distinction between null and undefined.
ndp
A: 

I prefer the concept of having non-nullable pointers be the default, with nullable pointers a possibility. You can almost do this with c++ through references (&) rather than pointers, but it can get quite gnarly and irksome in some cases.

A language can do without null in the Java/C sense, for instance Haskell (and most other functional languages) have a "Maybe" type which is effectively a construct that just provides the concept of an optional null pointer.

olliej
+3  A: 

Borrowing a page from Haskell's Maybe monad, how will you handle the case of a return value that may or may not exist? For instance, if you tried to allocate memory but none was available. Or maybe you've created an array to hold 50 foos, but none of the foos have been instantiated yet -- you need some way to be able to check for these kinds of things.

I guess you can use exceptions to cover all these cases, but does that mean that a programmer will have to wrap all of those in a try-catch block? That would be annoying at best. Or everything would have to return its own value plus a boolean indicating whether the value was valid, which is certainly not better.

FWIW, I'm not aware of any program that doesn't have some sort of notion of NULL -- you've got null in all the C-style languages and Java; Python has None, Scheme, Lisp, Smalltalk, Lua, Ruby all have nil; VB uses Nothing; and Haskell has a different kind of nothing.

That doesn't mean a language absolutely has to have some kind of null, but if all of the other big languages out there use it, surely there was some sound reasoning behind it.

On the other hand, if you're only making a lightweight DSL or some other non-general language, you could probably get by without null if none of your native data types require it.

Mark Rushakoff
Exceptions are unchecked, so if you can ensure that a situation doesn't occur, you don't have to try/catch.
Imagist
Technically you can never "ensure" that a situation won't occur, unless you have total control over all aspects of the hardware and software in question.
Chris Lutz
@Chris True, but there's reasonable assurance. Reads from files, network connections, and user input generally can't be ensured. However, if you have something like `x/2`, you can be reasonably sure that it won't throw a `DivisionByZeroException`.
Imagist
@lmagist: That's a bit of a strawman argument. Things like memory allocation are very commonplace and yet are never guaranteed to succeed.
Eric
A: 

I think it's usefull for a method to return NULL - for example for a search method supposed to return some object, it can return the found object, or NULL if it wasn't found.

I'm starting to learn Ruby and Ruby has a very interesting concept for NULL, maybe you could consider implementing something silimar. In Ruby, NULL is called Nil, and it's an actual object just like any other object. It happens to be implemented as a global Singleton object. Also in Ruby, there is an object False, and both Nil and False evaluate to false in boolean expressions, while everything else evaluates to true (even 0, for example, evaluates to true).

JRL
If a method failed at its job, it should throw an exception.
Imagist
A number of people aren't fans of exceptions. Joel has an entire blog post on the subject that's turning into the new Jamie Zawinski regex quote on this site.
Chris Lutz
@Chris Link? Also, it's worth noting that different languages use exceptions very differently. In C++ there are memory-leak dangers with exceptions, and in Java, checked exceptions are used improperly as often as not. Python, however, uses exceptions very effectively, to the point that it's usually better to try and catch errors than to check for errors beforehand.
Imagist
Another thing to note; returning NULL is slower than throwing an exception and catching it, especially if the actual handling of the failure occurs much lower on the call stack.
Imagist
@Imagist: you're right, my wording was wrong. I didn't mean failure here. As my example says, I mean when the method should return an object but that object isn't found, for example when searching. Without a NULL, there is no way to have such a method. In cases of failure, there should be exceptions. I changed my wording accordingly.
JRL
@JRL I disagree. Who says that not finding an object isn't failure? The point is that failure isn't always a bad thing, as long as it's handled.
Imagist
A: 

It's not clear to me why you would want to eliminate the concept of 'null' from a language. What would you do if your app requires you to do some initialization 'lazily' - that is, you don't perform the operation until the data is needed? Ex:

public class ImLazy {
 public ImLazy() {
  //I can't initialize resources in my constructor, because I'm lazy.
  //Maybe I don't have a network connection available yet, or maybe I'm
  //just not motivated enough.
 }

 private ResourceObject lazyObject;
 public ResourceObject getLazyObject() { //initialize then return
  if (lazyObject == null) {
   lazyObject = new DatabaseNetworkResourceThatTakesForeverToLoad();
  }
 }

 public ResourceObject isObjectLoaded() { //just return the object
  return (lazyObject != null);
 }
}

In a case like this, how could we return a value for getObject()? We could come up with one of two things:

-require the user to initialize LazyObject in the declaration. The user would then have to fill in some dummy object (UselessResourceObject), which requires them to write all of the same error-checking code (if (lazyObject.equals(UselessResourceObject)...) or:

-come up with some other value, which works the same as null, but has a different name

For any complex/OO language you need this functionality, or something like it, as far as I can see. It may be valuable to have a non-null reference type (for example, in a method signature, so that you don't have to do a null check in the method code), but the null functionality should be available for cases where you do use it.

RMorrisey
My language has built-in support for thunks. In this case the `ImLazy()` constructor would initialize `lazyObject = new Thunk(new DatabaseNetworkResourceThatTakesForeverToLoad());` (roughly; the syntax of the language is different). This way, even when getLazyObject() is called, the object is not initialized (it is initialized when something is done using it that would cause a side-effect). If you want to load the object before then, you can call `lazyObject.resolve()` to resolve the thunk. I'm also considering having a built-in thread that uses idle cycles to resolve thunks early.
Imagist
That seems like it makes sense. If you have a constructor with arguments, I guess you would store the arguments passed in until the Thunk initializes the object?
RMorrisey
Right. You don't actually pass in the object, you pass in the constructor and the arguments to the constructor.
Imagist
A: 

Interesting discussion happening here.

If I was building a language, I really don't know if I would have the concept of null. I guess it depends on how I want the language to look. Case in point: I wrote a simple templating language whose main strength is nested tokens and ease of making a token a list of values. It doesn't have the concept of null, but then it doesn't really have the concept of any types other than string.

By comparison, the langauge it is built-in, Icon, uses null extensively. Probably the best thing the language designers for Icon did with null is make it synonymous with an uninitialized variable (i.e. you can't tell the difference between a variable that doesn't exist and one that currently holds the value null). And then created two prefix operators to check null and not-null.

In PHP, I sometimes use null as a 'third' boolean value. This is good in "black-box" type classes (e.g. ORM core) where a state can be True, False or I Don't Know. Null is used for the third value.

Of course, both of these languages do not have pointers in the same way C does, so null pointers do not exist.

staticsan
A: 

We use nulls all the time in our application to represent the "nothing" case. For example, if you are asked to look up some data in the database given an id, and no record matches that id: return null. This is very handy because we can store nulls in our cache, which means we don't have to go back to the database if someone asks for that id again in a few seconds.

The cache itself has two different kinds of responses: null, meaning there was no such entry in the cache, or an entry object. The entry object might have a null value, which is the case when we cached a null db lookup.

Our app is written in Java, but even with unchecked exceptions doing this with exceptions would be incredibly annoying.

Mr. Shiny and New
Database nulls and language nulls are very different conceptually (there is actually a type distinction made in C#).
Imagist
@Imagist: I am not talking about database nulls, I am talking about the no-records-found scenario. For a method that returns a single object, you need some way to indicate that no object can be returned. An exception can do that, but it's very cumbersome to program that way, at least in Java. Maybe your language has some elegant approach that makes it easier. But in my experience null is very useful.
Mr. Shiny and New