How about removing Null-Pointers from programming languages?

Accname

2D-Graphics enthusiast
Reaction score
1,456
Hi there,

I was having some thoughts on the design of programming languages.
I got to the conclusion, that I really hate nullpointers. In my programs I usually try to create a subclass of a class which acts as a "null" reference; a class I use if the object is not really defined.
Why do I do this? Because it makes the code shorter. Instead of having branches to check for null references, I simply overload all functions in my "null"-subclass with empty methods and default values.
Sure, this doesnt work in all situations, but in many situations it does.

So I was thinking, why not integrate something like this in the programming language itself.
Each class could define a "null"-reference for its instances. If a class does not define an own null-reference then the reference from the super class is being used.
I think this could help enormously to cut down code size and make applications more stable.

What do you guys think?
 

Narks

Vastly intelligent whale-like being from the stars
Reaction score
90
4/10 troll

almost believed you for a second
 

monoVertex

I'm back!
Reaction score
460
You say it would make applications more stable, but it wouldn't. You're just treating the error silently, but if by mistake you use the null-like reference as an actual reference (the same way you'd use null as a reference), your application will still go south, but it doesn't give you an error that you tried to use a null value.

Or, let's say you get that reference as an input, you don't control it (you're working with a library you can't modify) and your app needs an actual reference. You still have to test if it's a dummy null or not.

Basically, whenever you're expecting some kind of output from the methods of your object, you're screwed if you're using this null dummy and not testing for the output. And if you're testing the output, then the code is even more bloated.
 

Accname

2D-Graphics enthusiast
Reaction score
1,456
Not neccessarily!
Yes, it would still go down in certain circumstances, and these are unavoidable because they are an important part of the application.
But there are many cases where this would be very helpful.

Just imagine a list, its null element is an empty list. You can not have a list reference which is >not< a list. Because "null" is not technically a list.

Or Strings. A "null"-String would be the empty string.
Right now, you do stuff like:
Code:
public void doStuff(String s) {
    if (s != null && !s.isEmpty()) {
        // do more stuff...
    }
}
Which is really upsetting me.

My thought is, that a real object-oriented programming language should not have any primitive data types or null-references.

Right now, if you have a variable myCar of type Car, you say that myCar is either a reference to a Car or null. But why should myCar ever be null? If I say I want myCar to be a Car then it should never be anything else but a Car goddammit!

Nullpointers are an obsolete left-over from the past. There is no benefit of having a null-reference over my method. But there are some benefits of having dedicated "null"-objects.
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
Hoare agrees with you. He once wrote this:

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. In recent years, a number of program analysers like PREfix and PREfast in Microsoft have been used to check references, and give warnings if there is a risk they may be non-null. More recent programming languages like Spec# have introduced declarations for non-null references. This is the solution, which I rejected in 1965.
When working on my own code I usually keep in mind which object references can be null and which can't - but it's troublesome, yes.

But - I can't imagine working completely without null. It would produce an ugly performance overhead in java. Removing null from general-purpose imperative languages would require some serious re-learning for everyone involved. Not that this would ever happen.
 

Accname

2D-Graphics enthusiast
Reaction score
1,456
I dont think so.

In my opinion the performance wouldnt suffer at all. When you assign a null-reference to a variable the compiler would only need to look in its class definition for the null-reference specified.
Each class would have its own static and constant null-pointer-object. This object is created when the class is loaded. When a class does not define its own null-pointer then the null-pointer of the super class is used, until you use the null-pointer from object.

The null-pointer object would work the very same way as a null-reference. You dont even need to change much about the syntax. You can add syntactic sugar so that you dont even have to change your code at all.
If one was to implement this into java right now, all legacy code would probably still work the same way.

By the way, many languages already have a null-object which is used instead of a null-reference. But they usually dont allow you to specify your own.
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
I see many problems, however. I'll use Java for examples.

First: If such a "null reference" is an object in "default" state (such as an "" string) then it's not possible to distinguish between a genuine object in default state and such a null object unless you compare it to the reference inside the class. So instead of "s != null" you now have to write "s != String.Null" or similar.

Second: What happens if you call methods of this object such as s.append("hi")? Will it simply fail silently? Very bad idea, hard to detect errors. Will it throw an exception? Then it's basically the same as using null. Will you allocate a fresh object and work on that one since you must not change your unique static null object? Then the null reference's use is very situational, but sounds like the only somewhat viable option.

Third: If a null object can still be used you can't travel up the object's inheritance hierarchy to find a null reference since you must ensure that it is of the correct type. So every class needs to have it's own null reference.

Fourth: How do you handle more complex objects with constructors? If I have an object that opens a File and stores it's pointer inside, how am I going to make a null-reference for that? I'd have to write every class with the thought in mind that I have to have a null object with no side effects.
 

Accname

2D-Graphics enthusiast
Reaction score
1,456
1) I dont think so. This is not a problem right now and it would not be a problem when this approach is taken.
If you want to know whether an Object has been initialized or not you could still use the condition "obj == null" and have the compiler use some magic to turn it into a proper null-object test.
You could also add another method to the Object class which is "public boolean isNull()" and returns true iff the object in question is a null-object.

2) First of all, you can not append anything to a String in java. Strings are immutable objects.
But for the sake of the example lets assume Strings were not immutable and they did indeed have an "append" method.
In my thought it could lead to a NullPointerException just the same way as if you were to write:

Code:
String s = null;
s.append("a");
Of course, one could also argue, that a new String should be constructed instead. I dont see anything wrong with either method since both have their merits.

The main focus of the idea is, that getters would work with null-references. Any kinds of methods which are supposed to change the state of an object would still throw a NullPointerException, but you could, for example, call the toString() method, the hashCode() method, the equals() method, the getClass() method, and many other useful methods on the object.

3) I would not implement it in a way, that each class has to specify an own null-object implementation. I would make it optional.
If a class does not define its own null-object then either a generic null-object is used, or the compiler creates a unique null-object at compile time.
This generic null-object would simply throw NullPointerExceptions when a method (other then equals, toString, hashCode, etc) is used.
This would be exactly the same as it is right now. I cant see why this would be a problem.

4) I dont see the problem with this either. Here is an example:
Code:
public class ComplexClass {
 
    public static final ComplexClass NULL = new ComplexClassNull();
 
    private final File file;
    private final DataOutputStream out;
    private final DataInputStream in;
 
    private ComplexClass() {
        file = null;
        out = null;
        in = null;
    }
 
    public ComplexClass(String path) throws FileNotFoundException {
        file = new File(path);
        out = new DataOutputStream(new FileOutputStream(file));
        in = new DataInputStream(new FileInputStream(file));
    }
 
    public void write(byte b) throws IOException {
        out.writeByte(b);
    }
 
    public byte read() throws IOException {
        return in.readByte();
    }
 
    private static final class ComplexClassNull extends ComplexClass {
 
        public void write(byte b) throws IOException {
            throw new NullPointerException("This is a null object");
        }
 
        public byte read() throws IOException {
            throw new NullPointerException("This is a null object");
        }
 
    }
 
}
As you can see, this even works with Java as it is.

---------------------------------------------------------------------

My point is, everything that is possible right now would still be possible if this was being used.
But many things can get easier this way, and I am yet to find an example that would get harder or more complex.

---------------------------------------------------------------------

Edit: Just some examples to bring my point across:
From Java's LinkedLis:
(http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/LinkedList.java#LinkedList.<init>())
Code:
    public boolean remove(Object o) {
        if (o==null) {
            for (Entry<E> e = header.next; e != header; e = e.next) {
                if (e.element==null) {
                    remove(e);
                    return true;
                }
            }
        } else {
            for (Entry<E> e = header.next; e != header; e = e.next) {
                if (o.equals(e.element)) {
                    remove(e);
                    return true;
                }
            }
        }
        return false;
    }
From Java's EnumMap:
(http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/EnumMap.java)
Code:
    private static final Object NULL = new Object();
 
    private Object maskNull(Object value) {
        return (value == null ? NULL : value);
    }
 
    private V unmaskNull(Object value) {
        return (V) (value == NULL ? null : value);
    }
Code:
        public int hashCode() {
            if (lastReturnedIndex < 0)
                return super.hashCode();

            Object value = vals[lastReturnedIndex];
            return keyUniverse[lastReturnedIndex].hashCode()
                ^ (value == NULL ? 0 : value.hashCode());
        }
Just look at this mess. Its disgusting that developers think they have to deal with this.
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
But I don't get how you want to work with null objects.

You've mentioned this example

Code:
public void doStuff(String s) {
    if (s != null && !s.isEmpty()) {
        // do more stuff...
    }
}
and that you are tired of doing so. But with null objects, would you not write:

Code:
public void doStuff(String s){
    if ( !s.isNull() && s.isEmpty()) {
        // do more stuff
    }
}
?

I don't see the benefit of exchanging the generic null keyword with a non-generic class. Because if you only write s.isEmpty() in the example, you still don't know whether you got a genuine empty string or a null object. In this case it's not all that important, but it will be a serious issue if you use values returned by getter methods and continue to work on them, even though you've been given a null object. In this case your problem has failed silently and your code hasn't noticed. With null, you get a crash in your face immediately. (Not in all cases, but in most.)
 

Accname

2D-Graphics enthusiast
Reaction score
1,456
That was maybe a bad example I gave.

The examples I gave in my previous post (after editing it) are taken directly from existing code and showcase perfectly how this would improve simplicity of programs.

I think you try to read too much into this idea; its not my thought to catch any kind of NullPointerException silently.
In my opinion NullPointerException would still be thrown a lot.
But now the developer would have the possibility to deal with them silently if he so chooses.


But just for you, here is an example from real life, this was a piece of code I had to write for a computer science class:
Code:
public class UserBean {
    
    private String name;
    private String password;
    
    public UserBean() {
    }
    
    public void setName(String name) {
        if (name == null
            || name.isEmpty()
            || containsIllegalCharacters(name)) {
            throw new IllegalArgumentException();
        }
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
    
    public void setPassword(String password) {
        if (password == null
            || password.length() < 5) {
            throw new IllegalArgumentException();
        }
        this.password = password;
    }
    
    public String getPassword() {
        return password;
    }
    
    private boolean containsIllegalCharacters(String s) {
        if (s == null) {
            throw new IllegalArgumentException();
        }
        for (int i = 0; i < s.length(); i++) {
            char chara = s.charAt(i);
            int type = Character.getType(chara);
            if (type != Character.LOWERCASE_LETTER
                && type != Character.UPPERCASE_LETTER) {
                return false;
            }
        }
        return true;
    }
    
}
This could have been simplified by removing all those pesky "s == null" conditions.
Of course, this is already pretty simple. This is not a big deal. But its just a quick example of an actual use-case.
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
Well, all those pesky null equality conditions add up to three. One of them being redundant.

But the idea comes across, of course. However, I think the idea should go the other way.
I quite like the Haskell way of implementing a Maybe. If I'd map it on to Java I'd look like this:

Code:
public void setPassword(String s){
    //s must always be a valid String object
}
public void setEmail(Maybe String s){
    if( s != null ) //Maybe String can be null
        ....
}
C++ handles it in a similar way. Objects must always be valid, only pointers to objects can be null.

As long as you have a null or anything that directly takes it place, you'll always have to struggle with annoying validity checks.

Null objects pose a massive problem if they are half-functioning. If you have a function that doesn't check whether a parameter is null, you either expect it to always be non-null or you forgot. Either way, if this parameter is a null object you'll get a silent failure that is probably not intended by the programmer due to oversight. It's better to fail with an exception rather than take the chance that program execution continues with bad data.

With isEmpty() it might not be a big deal, but it would be much worse.

Code:
class TCPPort{
    public int getPortNumber(){ return m_port; }
    private int m_port;

    private static final class EmptyTCPPort extends TCPPort{
        public int getPortNumber(){ return 0; }
    }
}

class SomeClass{
    public void openPort( TCPPort p ){
        java.awesomepackage.somethingsomething.openPort( p.getPortNumber() );
    }
}
That would crash if p == null, but would not crash if p is of type EmptyTCPPort. Now, you could argue that EmptyTCPPort is a bad implementation of a null object for TCPPort, but String.isEmpty() (or rather .size()) is basically the same as TCPPort.getPortNumber(). We have a getting returning a default value. But now we are accidently trying to open port 0.
 

Accname

2D-Graphics enthusiast
Reaction score
1,456
Well, all those pesky null equality conditions add up to three. One of them being redundant.
Yeah its hard to find a good real world use-case on the fly. Theres probably many good examples for this, but finding one exactly when you need it is not that easy.

I quite like the Haskell way of implementing a Maybe.
Yes, thats a good concept too, but makes for longer code.

Null objects pose a massive problem if they are half-functioning. If you have a function that doesn't check whether a parameter is null, you either expect it to always be non-null or you forgot. Either way, if this parameter is a null object you'll get a silent failure that is probably not intended by the programmer due to oversight. It's better to fail with an exception rather than take the chance that program execution continues with bad data.
This is where I completely disagree.
Again, these null-objects are not meant to just silently take any abuse the programmer might be up to.
Of course, you COULD do something stupid with it, like in your example, but thats not what they are meant for.

If you look at the examples I took from the java standard library, you will see how the java developers are doing all kinds of stupid mess just to ensure that you can add & remove the null reference in their collections.
But they have to write separate code for these situations.

I want a null-object with good "equals", "hashCode", "toString" and other methods. Nothing that adds a major functionality to the null-object; its just convenient.
And then, on top of that, you give the possibility to do other stuff with it. Nobody is forced to use their own null-objects. Nobody is forced to silently swallow NullPointerExceptions or give bad return values.
But if they really want, then they can.
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
If it's an object that only does not throw when you call one of it's methods inherited from Object by default then I find it more reasonable. Especially .equals() would be useful.

But I'm not convinced that it wouldn't lead to more trouble than it's worth - especially if classes from the Java Standard Library would start using this (and you'd have to keep in mind which are throwing and which aren't).

Silent failure is probably the most devilish behavior your program can exhibit, and it sounds like this could yield some very unexpected silent failures.

My TCPPort example still holds true. If some dev thought it would be a good idea to "overload" getPortNumber() for the null object, the error of not checking a TCPPort against null would cause trouble.
If you only limit yourself to making non-essential methods work (debug/output msgs, logging, etc) and that every method that has a hand in executing the actual program still throws, you could get rid of that.

I'd still prefer a language that guarantees me that an object is valid, or that clearly shows me if it can be null (Maybe or the C++ model). Why have an EmptyString class when an empty String can do the same job. And if it's a heavy-weight object, you make it a Maybe X (or pass a nullable ref/ptr).
PS: Does everyone get a mess of HTML coding when they click on the Edit button? Pretty annoying.
 

Accname

2D-Graphics enthusiast
Reaction score
1,456
Your CPPort example can be constructed with the code right now. If a dev implements it this way it will still be crap, whether a null-object is used or not. So I dont see your argument at all.

But I guess its personal taste.

by the way, I also have this HTML-stuff when editing a post. But if I remember correctly this only happens with certain browsers; for me it happens with firefox 25.0.1.
 

Accname

2D-Graphics enthusiast
Reaction score
1,456
Now that we were talking about Haskell I just had to implement the Maybe data structure in Java, have a look, maybe you will like it:
Code:
public class Maybe<T> {
    
    /**
     * This constant Maybe instance is used as a reference to 'Nothing'.
     */
    private static final Maybe NOTHING = new Maybe() {
        public int hashCode() {
            return 0;
        }
        
        public boolean equals(Object other) {
            return this == other || null == other;
        }
        public String toString() {
            return "Nothing";
        }
    };
    
    /**
     * This method returns a 'Nothing' instance of Maybe.
     * @return 'Nothing'
     */
    public static <T> Maybe<T> NOTHING() {
        return NOTHING;
    }
    
    /**
     * This method returns a 'Just obj' instance of Maybe, 
     * or a 'nothing' instance of Maybe if obj == null.
     * @param obj - the object to be encapsulated.
     * @return either 'Nothing' or 'Just obj'
     */
    public static <T> Maybe<T> JUST(T obj) {
        if (obj == null) {
            return NOTHING;
        }
        return new Maybe<T>(obj);
    }
    
    private T content;
    
    private Maybe() {
        this(null);
    }
    
    private Maybe(T obj) {
        content = obj;
    }
    
    public T get() {
        return content;
    }
    
    /**
     * If true this is nothing and get() will return 'null'.
     * @return
     */
    public boolean isNothing() {
        return content == null;
    }
    
    /**
     * If true this is not nothing and get() will return an object.
     * @return
     */
    public boolean isSomething() {
        return !isNothing();
    }
    
    /**
     * Hash code of encapsulated object
     */
    public int hashCode() {
        return get().hashCode();
    }
    
    /**
     * Nothing == Nothing
     * Nothing == null
     * Just A == Just A
     * Just A == A
     */
    public boolean equals(Object other) {
        if (other instanceof Maybe) {
            return get().equals(((Maybe<?>) other).get());
        }
        return get().equals(other);
    }
    
    public String toString() {
        return "Just "+get();
    }
    
    public static void main(String[] args) {
        
        Maybe<String> m1 = Maybe.NOTHING();
        Maybe<String> m2 = Maybe.JUST("Test");
        Maybe<String> m3 = Maybe.JUST("Something");
        Maybe<String> m4 = Maybe.JUST(null);
        
        System.out.println("m1 "+m1+" equals(null) "+m1.equals(null));
        System.out.println("m2 "+m2+" equals('Test')"+m2.equals("Test"));
        System.out.println("m3 "+m3+" equals(Just Something) "+m3.equals(Maybe.JUST("Something")));
        System.out.println("m4 "+m4+" equals(null) "+m4.equals(null));
    }
    
}
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
I quite see uses. I don't know if I'd want Maybe<>'s to be used everywhere there is a nullable object, but at least for return values it's useful.
 

Accname

2D-Graphics enthusiast
Reaction score
1,456
Nah, I wouldnt use it personally. Too much to write, too much garbage collection to be done.
I just love to code stuff.
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
There probably isn't much gc'ing involved. Allocations for wrapper and objects with short live time are often optimized away.

I'd rather have a little bit more to type than a little bit more details to remember when I code :p
 

Accname

2D-Graphics enthusiast
Reaction score
1,456
I never pass NullPointers around anyways.
I usually create a new empty object like in the way I described in this thread, or I throw / catch exceptions.
But cutting down code, to make it more readable and easier to understand is an important thing for me.

Thats why I dont like the listener-model that is used in swing. Every tiny bit of functionality becomes bloated up. I prefer a simple signal-slot system like in qt or similar. I want to write just 1 line of code to give my button a purpose.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • jonas jonas:
    Which company do you work for?
  • vypur85 vypur85:
    Haha yea they'd compare my country as well...
  • vypur85 vypur85:
    Hmm i don't receive any pm? Maybe I'm using my phone. Gonna check it out using my pc later.
  • vypur85 vypur85:
    I'm teaching A Levels in a school in Wuhan.
  • jonas jonas:
    You should see a "private conversations" tab in the chatbox, that's where I sent it to you
    +1
  • jonas jonas:
    Wow
  • jonas jonas:
    Is the school system in your country similar to Chinese school system? I could never imagine being a teacher in a Chinese school, what's expected of students and teachers is just so different from what I'd be looking for as a teacher
  • vypur85 vypur85:
    A Levels is based on the UK syllabus offered internationally. So the syllabus is similar throughout different countries, taught in english.
  • vypur85 vypur85:
    I can't speak or write or read much chinese... Too difficult....... Which also makes my life here in china a lil difficult.
  • jonas jonas:
    Oh, I see. I thought Chinese version of A-levels :D
  • jonas jonas:
    I've been using the translate app a lot on my phone. take a photo, translate. take another photo, translate again :D
  • jonas jonas:
    it also has voice translation, my colleagues sometimes use that
  • jonas jonas:
    You came during the 0 covid policy right? How'd you get through quarantine? Did you have some help with the apps and green codes?
  • tom_mai78101 tom_mai78101:
    If you have any Chinese you need help with, let me know.
  • vypur85 vypur85:
    @jonas Those were the things I did too. Translate app and VPN are always the most important things to have to survive. Lol.
  • vypur85 vypur85:
    Yea I came last year. I was quarantined for about 30 days. Fml. The first day of my quarantine was the eve of Chinese new year last year. Fml again... Lol.
  • vypur85 vypur85:
    @tom_mai78101 IIRC you're from Taiwan right.
  • The Helper The Helper:
    I thought China had cracked down on having any foreign teachers?
  • vypur85 vypur85:
    Yeah I've heard of the news before. My school is still actively hiring foreign teachers. Not sure how things work now.
  • The Helper The Helper:
    yeah it is hard to get reliable information about that kind of stuff
  • The Helper The Helper:
    but you are doing it so it is still doable
  • vypur85 vypur85:
    I think it doesn't affect existing foreign teachers. Then again, its still weird that my school is hiring.
  • The Helper The Helper:
    Happy Monday people hope everyone has a fantastic week!
  • Ghan Ghan:
    Happy Monday?! That's a contradiction.

    The Helper Discord

    Staff online

    Members online

    Affiliates

    Hive Workshop NUON Dome World Editor Tutorials

    Network Sponsors

    Apex Steel Pipe - Buys and sells Steel Pipe.
    Top