Mar 17, 2009

Null-safe method invocation in Java 7

There has been some discussion on null-safe method invocation in Java 7. Briefly there is a proposal to introduce a new ?. operator that would allow to call a method on a null object without throwing a NullPointerException (NPE). For instance:

   List list = null;
System.out.println(list?.isEmpty()); // prints: false

The most obtrusive part in the current state of proposals is assumption that the invocation on null object should always return null or a default value in case of primitives. In our example of list?.isEmpty() returning true would make much more sense then false, because semantically the null list does not have any elements so it is empty. The bottom line is that what the method returns when called on a null object is an implementation detail of that method, so it should be specified in the method's body. The rest of this post proposes a way to do it.

If the method's body starts with if (this == null) statement, e.g.

   class List {
public boolean isEmpty() {
if (this == null) return true;
return data.length == 0;
}
}

then Java 7 compiler could compile it to both the traditional method:

   public boolean isEmpty() {
// the if (this == null) ... block is removed
return data.length == 0;
}

as well as to a static wrapper method:

   private static boolean isEmptyNullSafe(List _this) {
if (_this == null) return true;
return _this.isEmpty();
}

(The name of the wrapper method must be generated by the compiler to prevent name clashes with methods already existing in the source code)

This way the isEmpty() method would work the same way if called normally:

   list.isEmpty()

, throwing NPE.

But the null safe call:

   list?.isEmpty()

would compile to:

   List.isEmptyNullSafe(list);

and return true, if the list is null.

12 comments:

  1. I would prefer using an annotation. Perhaps:

    @NullSafe("return true;")
    public boolean isEmpty()
    {
    return data.length == 0;
    }

    Randy

    ReplyDelete
  2. I like the annotation suggestion.

    MrOhad

    ReplyDelete
  3. This seems to me like trying to hide mere symptoms, instead of removing the primary source of the problem. The primary problem is the existence of 'null' in Java - and the fact that any field or variable of type "reference" can be initialized to 'null' or at any time can become 'null'. Trying to raise the level of program correctness by introducing the operator '?' or the annotation @NullSafe is a very weak idea.

    How can someone think it makes sense to ask the object "null" whether it is empty? This does not make any sense. In fact, you are proposing to be able to ask "null" any question (i.e. send it any message, invoke any method on it).

    ReplyDelete
  4. Why didn't the author of this blog entry send his comments about null-safe invocation to the coin-dev mailing list?

    If he had done so, many more people could examine his idea and it would be in the OpenJDK mail archives forever. This would be much more useful than the idea sitting on a personal blog (which could disappear at any time) and where only a handful of people will comment.

    ReplyDelete
  5. @Randy & @MrOhad
    Using annotations was my original thought. But according to the Sun guys annotations are not to be used for language features. And if you look at it, you put code, that you expect to compile, into your annotation. That is beyond what annotations are intended to for (meta-data).

    ReplyDelete
  6. @⚛
    I think it is to late to remove null from Java, because of backward compatibility requirement. The reason behind the proposed null handling improvements is pragmatism. NPE is the most often thrown exception and we're usually too lazy to check against null always when it is needed. The new operator will make it very easy and much more readable.

    From philosophical point of view it make a lot of sense to me as well. If you define variable
    Person person;
    then you may expect it to handle the message getName(), because it is of type Person and the contract of Person class obligates so. If it is null, then it can be viewed as "a person", rather then "the person".
    Besides null is not an object so I cannot be proposing to ask it any questions or invoke any methods on it.

    ReplyDelete
  7. @Jacek
    I cannot agree with most of what you just wrote. I can imagine only one reason why it is too late to create a (backward compatible) version of Java preventing references to objects such as "Person" to be nullable: human laziness. Especially laziness of people who designed the Java language.

    I don't think that if "Person person;" is null then it can be viewed as "a person". The Java-object representing the concept "a person" is most certainly "Person.class". I treat equaling "null" with "a person" to be unsound reasoning.

    Whether null is or is not an object: Rest assured, "null" is a mathematical object. The fact that Java is not calling "null" a Java-object is Java-specific. Java's notion of null cannot invalidate the mathematical properties attributable to the mathematical object "null". As a sidenote, "null" is an object in Smalltalk and you can send it messages (i.e. ask it some questions, invoke methods). Imagine having class "java.lang.Null" and a static final field "java.lang.Null.instance" of type "java.lang.Null".

    ReplyDelete
  8. there is one more issue in nullsafe method,
    bcoz a ref. var does not know which type of object it hold, as method are dynamic dispatched so hows it cud be staticaly attached to one method.

    ReplyDelete
  9. It really couldn't be simpler to join coin-dev and have the important discussion of null's role there.

    The fact that the conversation is continuing at this blog makes me think that the author is not serious about his proposal, and that he doesn't really want the wider community to consider it.

    ReplyDelete
  10. Don't allow the .? operator to assign to primitive type variables.
    Just like the compiler doesn't allow methods that return void to assign to variables.
    Just like the compiler doesn't allow the literal null to be assigned to primitive type variables.
    Just like the compiler doesn't allow the literal "foo" to be assigned to non-String variables.

    ReplyDelete
  11. @Vinod Pahuja
    You are wrong. If your reasoning is applied to a field or variable of type "int", it would mean that it is impossible to work with integers because an "int" is represented as raw binary data and does not know which type of object it holds.

    ReplyDelete
  12. @Vinod Pahuja
    I guess the static null handling method should be taken from the declaration class of the variable. If the variable has a non-null value (can be a sub-type), then there is no need to worry about null-safe methods :-)

    @Alex Buckley
    I posted to coin-dev, not without grumbling though since it uses mailing list - the most primitive collaboration tool ever, does not even have news server.

    @Geoffrey De Smet
    I agree that would be the most easy way to implement ?. operator. But such waist of flexibility would be too pitiful for me.

    ReplyDelete

Note: Only a member of this blog may post a comment.