Skip to main content

I swear, I don't want to talk about Java 7 language in details...

Posted by fabriziogiudici on January 11, 2007 at 3:36 PM PST

... but most of the replies to my previous post "Where are we going?" (also at TheServerSide follow-up) ended up talking about closures etc. It sounds like nowadays it's inavoidable to talk about code and syntax. Too bad. I thought that my next post would have focused on the "process" concept (since it looks like there's a sort of language barrier), but I'm postponing it and getting into the mud. ;-)Ok, I was kidding. Serioulsy, I don't want to be involved in the syntax debate. I'm just taking an example and showing how focusing too much on the code makes you loose sight of other problems.

Let's take for example Stephen Colebourne's proposal about a special # operator which deals with possible null dereferencing. From his blog:

The proposal introduces an alternative to the dot for method and field invocation, the hash - #. Using the hash invokes a method or field in the same way as using the dot, but with one change. If the expression on the left hand side of the hash is null, then the result of the expression is null. If the expression type is a primitive then zero or false is returned instead of null. If the expression is a void, then no action occurs.

For instance:

    public String getPostcode(Person person) 
      {
        if (person != null) 
          {
            Address address = person.getAddress();
         
            if (address != null) 
              {
                return address.getPostcode();
              }
          }
        return null;
      }

would be coded in the really shorter:

    public String getPostcode(Person person) 
      {
        return person#getAddress()#getPostcode();
      }

Looks neat, doesn't it? Stephen says: "When they do code the null-checks, maybe due to unit tests, UAT or a production issue, the code suddenly loses all readability, and the real intent of the method is lost". At first sight it sounds reasonable - I must admit that sometimes all those "if" keywords annoy me too.

But why don't we look at the problem from a broader perspective?

While short code sketches are the first thing that comes in mind to illustrate the purpose of a syntax enhancement, they are not enough to fully evaluate its impact on the real world. Crawling at the code level prevents us from seeing at a distance - let's climb to 10000 ft and see from an AWACS perspective. Keep this latest concept in mind: at the end of this post you might disagree with me and my vision about coding styles, but at least you won't have missed a deeper analysis of the problem.

My first question is: what is the semantic meaning of address == null? Is that null a valid, expected value for that entity or a bug?

Let's say it's a valid value. Well, being null is always a special case for an entity. In this case I say that the if (address != null) is just self-documenting and thus it should not be removed; the programmer who wrote it did it properly. Removing it makes the code less readable, in the sense that it's harder to understand at a glance that all the expected cases are handled properly. In other words, the few more lines reflect a real complexity of the scenario being dealt with.

Now let's consider the other case: it's an invalid value. It should never happen. In this case, is the return null fallback case ok? The null might be have been added by a programmer in a hurry, maybe on the fly when an annoying NPE occurred just before a demo (let's be honest, we all did something like this at least once in our life) and then forgotten. This is obviously very bad. Being an error case, a better code could be:

try
  {
    return person.getAddress().getPostcode();
  }
catch (NullPointerException e)
  {
    return null;
  }

where the catch better documents that we are dealing with some exceptional case. If you really don't like the try/catch, stick with the original code, but add a short comment near the if.

But this it's not satisfactory yet. Is it ok to return null or would it be better to return an empty string? Which is the effect of that null being returned? Are you sure that that it won't trigger another NPE? And, still in a hurry, you will manage it in the same way? Again and again, until you get to the GUI and have a "null" shown in a textbox, and then somebody else will be wondering "where does that f***ed null come from?".

Please note that with the # operator not only the code won't be able to document all these semantically different scenarios, but most programmers anxious of saving a couple of keystrokes will always write the wonderfully short notation person#getAddress()#getPostcode(), "just to be safe", and won't get aware of all the above.

My point is, if a null address is not a valid case, let's stick with this:

    public String getPostcode(Person person) 
      {
        return person.getAddress().getPostcode();
      }

after all exceptions in low-level classes should be thrown, and caught at upper levels.

I repeat, you might disagree with this coding style - and I wouldn't probably code like this in all cases. This post is not about coding styles, it's about perspective. Give the # operator to junior programmers, they will code faster but they will loose a lot of perspective. Force them to use a few more lines of code, and they will be much more aware of what they are doing.

Last but not least, you must keep the control of that null with testing. While a wandering null could go unnoticed in a test case, especially in a world filled with # operators, thus giving a false sense of stability, a NPE won't.

IMHO the NPE is your friend, since it carries along the detailed information about where the error occurred (the stack trace was one of the features of Java that made me love the language since the very beginning).

So, if we really want to keep the # operator, at least let's use a new keyword: jptnbh (just pretending there's no bug here ;-).

PS Stephen considered correctly in his post that there are "a few corner cases where returning null/zero/false is inappropriate":

object#equals(null);   // returns false when object is null, but should return true
list#isEmpty();        // returns false when list is null, but would prefer to return true

To solve this, he proposes a special static method to deal with it:

public class Object 
  { 
     ...
     public static boolean #equals(Object other) 
       {
         return (other == null);
       }
  }

That is, to save a few lines in the application code, we are bloating the Java runtime (a common consequence of the "devil is in details" pattern). Is it still KISS?

Related Topics >>