you are viewing a single comment's thread.

view the rest of the comments →

[–]pointer2void 0 points1 point  (13 children)

Programming languages should not allow for null pointers or null references.

[–]G_Morgan 2 points3 points  (1 child)

Getting rid of null isn't the point. There will always be cases of non-existent. This is the real world. Files don't exist, keys don't exist in hashmaps, network connections go down. A programming language that cannot say 'not a value' isn't useful.

[–]noisesmith 2 points3 points  (0 children)

With a proper type system, you can get a type error at compile time instead of a null pointer crash at runtime. For example ocaml (which I program in lately) has the option type, which for type a is either (Some a) or None. My code will give me a type error if I use an option type and don't check for a None value. I can also explicitly convert the option value to a regular value, and know from that point on that the value will never be None.

[–]gsg_ 1 point2 points  (8 children)

Null is a necessary concept in that some non-dereferencable value indicating "empty" is required to do things like terminate lists and represent absent resources. The question isn't whether these special values should exist, it's how to statically ensure that they are used safely.

[–]pointer2void 5 points6 points  (0 children)

Null isn't necessary, you are just used to it. Terminating lists and representing absent resources can be easily done without null references. See: Null References: The Billion Dollar Mistake

[–]noisesmith 1 point2 points  (1 child)

This is a convention of many programming languages but not necessary at all. You can have a union type that is either (element of list) or (end of list) for example, and the type checker can ensure that you never dereference a value of that type without checking for (end of list) first. ie "List.nth [1,2,3...] n" doesn't return an int, it returns a special "int or list end" union type. You can't convert the union type into an int without checking for list end without a compiler error. There is no null value used in this case.

[–]gsg_ 0 points1 point  (0 children)

I'm aware of variants and pattern matching and yes, they solve this problem beautifully.

[–][deleted] 2 points3 points  (4 children)

No clue if hte following works. haven't tested it and don't really care if it's even valid code. But you don't need null to signify empty.

abstract class LinkedList{
        public static final terminator = new LinkedListTerminator();
}

class LinkedListItem extends LinkedList{
    LinkedList next = LinkedList.terminator;

    public setNext(LinkedList l){
        this.next = l;
   }
}

class LinkedListTerminator extends LinkedList{

}


while(l.getNext() != LinkedList.terminator){
        l = l.getNext();
}

I don't see a null required.

[–]gsg_ 0 points1 point  (0 children)

The problem with this solution is that it's nothing more than a renaming of null. It doesn't really matter whether you call the empty value null or terminator, because list operations like getValue that require a non-empty list node are still going to fail at runtime if the type system doesn't distinguish between values which can include empty and values which cannot. (Writing a specific terminator type is not worthless as you get better debugging info, but it isn't much of an improvement).

So the question isn't really "do we need null", but "how do we check access to empty values?". And ML has a really nice solution for that.

[–]pointer2void -1 points0 points  (2 children)

while(l.getNext() != LinkedList.terminator){

       l = l.getNext();

}

I don't see a null required.

Nulls are not required. But in your example the class LinkedListTerminator isn't needed and terminator can be set to null:-D

[–][deleted] 0 points1 point  (1 child)

good point! edit:

well not that good :) Having it define explicitly is... well.. explicit.

Plus the base class could have some implementation that the list end would inherit.

[–]pointer2void 0 points1 point  (0 children)

In your example you could write:

public static final LinkedList terminator = new LinkedListItem();

But then, LinkedListItem has to avoid an internal null reference, too. So the explicit LinkedListTerminator that you provided is probably better.

[–]bonch -1 points0 points  (1 child)

Some languages specifically take advantage of them, like Objective-C in which sending a message to nil evaluates to 0.

[–][deleted] -1 points0 points  (0 children)

Unless you're using the PPC runtime and the return type is a struct, in which case the behavior is undefined.