 |
I swear, I don't want to talk about Java 7 language in details...
Posted by fabriziogiudici on January 11, 2007 at 03:36 PM | Comments (15)
... 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?
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
... and this triggers another question: what is the main purpose of a programming language, teach juniors about how to code, or serve as a tool to do something useful?
Posted by: ronaldtm on January 11, 2007 at 04:40 PM
-
A good response, even if I disagree with most of your points ;-) You might want to review the other half if the proposal null-safe types too. The two parts were intended to work together as a whole.
In particular, I disagree with the notion that forcing a junior programmer to write a null check will make them more aware of what they are doing. Only if every != null check explains why it exists in a comment do you actually achieve the nirvana that you are describing.
Oh, and did you know that the equals() method is pretty broken right now? Consider that a.equals(null) returns false, but null.equals(a) throws a NPE. They should really be symmetric :-)
Posted by: scolebourne on January 11, 2007 at 04:48 PM
-
Well, that's what you get with a mainstream language ... a never ending concern about "Java Joe" and about "junior programmers".
Java is a platform ... it could support 2 official languages ... one for experienced programmers and one for juniors.
But nooo ... we keep going back and forth, and out of all this fight we end up with broken features.
Posted by: bonefry on January 11, 2007 at 05:09 PM
-
@ronaldtm: Useful things are those things that work. Since I've not seen yet a development team made only by seniors, I think we must be concerned about the quality of the code written by juniors - possibly preventing errors.
And yes, a programming language should promote learning and improving, as not only the teaching quality in high schools and universities is often questionable (obviously I'm talking of the masses), but our job gets more and more complex as technology evolves, and everybody has to be in continuos learning mode.
@scolebourne: I don't want to get in the debat about details. :-) Unless until there will be a pre-filtered and limited number of syntax enhancement proposals on the carpet. I just took your proposal as an example.
Still keeping myself at 10000ft ;-), that is not going into details, I think that your proposal about null-safe types a completely different approach, that I like: instead of starting from the purpose of saving some lines of code, it basically makes the language richer by better describing types. Coming down to earth, lines of codes are saved as a side-effect. This is the right way to do IMHO.
Posted by: fabriziogiudici on January 11, 2007 at 05:11 PM
-
Another thing. I get your point about simmetry, but doesn't disturb me too much as in my view methods can be invoked only on non-null objects. What about just adding this without the need of a new syntax?
public class Object
{
public static boolean equals (Object a, Object b)
{
if (a == b) return true;
if (a == null) return false;
return a.equals(b);
}
}
At this point, Object.equals(a, null) returns false and Object.equals(null, a) returns false with no NPE (disclaimer: it could be severely broken, it's very late on my locale and I really should go to sleep - my point is let's try first to solve problems with the current tools, and search for new tools only if the problem can't really be solved).
Posted by: fabriziogiudici on January 11, 2007 at 05:21 PM
-
I disagree with Stephen's proposal completely - the # operator would most likely be used instead of the '.' operator out of fear of NPEs, hiding them.
With method references, which I'm sure I've seen touted somewhere for Java 7 (Danny Coward's presentation, perhaps), tolerating null could be written without further language change:
String lowercase=tolerateNull(string,String.toLowerCase);
The same thing could be chained for multiple possible nulls, e.g.
String address=tolerateNull(tolerateNull(person,Person.getAccount),Account.getAddress);
Yes, I know that's ugly. I don't think there's a shorter way without Stephen's proposal. I also don't think a shorter way, or any way, is needed. Just as global variables are effectively banned by sentient programmers, why not get rid of null? There are only a few corner cases where null itself is actually needed, and those that I know of are because Java doesn't have tail call optimisation.
With things like the Maybe type from Haskell, most code can be null-free. I like Stephen's other proposal, because it resembles Maybe.
Posted by: ricky_clarkson on January 11, 2007 at 05:25 PM
-
I'd also like to take a moment to disagree with Fabrizio - the part about catching NullPointerException will, as I believe Stephen has already pointed out elsewhere, catch NPEs within the methods called.
This is not desirable, only the dereferences that we can see in the method call are to be null-safe.
Posted by: ricky_clarkson on January 11, 2007 at 05:29 PM
-
The catch example was only an intermediate passage. The solution I would use more likely is the last one, that is at this level I would just let NPE to happen.
In any case, supposing that somebody put the catch inside the method, that would document that the method itself is taking the responsibility to handle an error - even coming from lower levels - , wrong or right might it be. If you want to handle errors only at the current level, keep the if's.
Posted by: fabriziogiudici on January 11, 2007 at 05:47 PM
-
@fab: "... 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."
The mere fact that, from talking about higher-level concerns than code you've been compelled to deal at code level by all the responders to your previous posting demonstrates perfectly the narrow-minded code obsessed view that you were trying to drag people out of.
I fear this post will simply fan those flames some more - what a shame.
@ronaldtm: "... and this triggers another question: what is the main purpose of a programming language, teach juniors about how to code, or serve as a tool to do something useful?"
Absolutely and certainly the latter - if you've been taught the correct concepts for programming you can use any language so long as you accept that it might introduce new constructs you've not seen and adapt accordingly (no use trying to do OO in 'C').
And, if we're all "grown-ups" we should all be able to agree to strive towards keeping the language simple and expressive maybe accepting that some features should not be added in order to preserve it's core heritage. Rather than getting utterly obsessed with the minutae.
Posted by: dancres on January 12, 2007 at 03:50 AM
-
@dan "I fear this post will simply fan those flames some more - what a shame."
I fear this too. Probably there could be also a language barrier here to blame on me, but I think that it's really a code over-excitement :-)
Posted by: fabriziogiudici on January 12, 2007 at 04:14 AM
-
hi Fabrizio, (blogsphere is a small town, isn't it?)
you know i'm not so much inside that java world but i have my 2 cents to spare:
this is not about the language or the platform, it's about the man behind the screen: can the average-Joe understand that a piece of code is self-documenting? i think not. i think average-Joe will take a piece of code as "given" and repeat it to death as a mantra, without never fully understand "why" and "how": i tend to agree with Stephen Colebourne point of view: give juniors some shortcuts while leaving full control of what is going on to the masters (or to the juniors smart enough to be able to grow up) of the platform.
Posted by: giuseppegrasso on January 12, 2007 at 03:05 PM
-
<personal-communication>
giuseppe, quanto tempo è passato! Scrivimi: fabrizio dot giudici at tidalwave dot it (però non potrò risponderti fino a martedì, sono in partenza)
</personal-communication>
Posted by: fabriziogiudici on January 12, 2007 at 03:19 PM
-
I see a much different problem: The world is not only divided into junior and senior developers, but also in those trying to do good engineering work and those just wanting to earn money. There are out too many who would do everything for a two minute hack. You will see coding in any larger project rapidly scattered with #'s, making sense at that place or not. This definitely would make tracing bugs much more difficult.
Posted by: rbirenheide on January 13, 2007 at 12:31 AM
-
HAHAHA oh man thats funny. I have never actually met a senor java programmer (I'm not conceded enough to count myself). I have to fix code all day long that that does things like this:
try{
//..do something complex
}catch(Exception e){}
Or this:
String s = new String("My new String");
Every time I read that I think, "Is there really a reason to make a copy?" but there never is.
Or this monstrosity:
new Thread(){
public void run(){
sleep(5000);
System.gc();
}
}.start();
Please don't give people another way of hiding their bugs from me. The # operator will only percolate the error up into code thats smart enough to check. This will make bad code run and good code throw up, and thats just going to make things look real bad for the people who try hard to write good code.
Posted by: aberrant on January 15, 2007 at 03:46 PM
-
2fabriziogiudici: Object.equals( o1, o2 ) is very useful especially when comparing two strings. But I think it is more nice to implement a new equals operator for it e.g. "?=".
The idea of a new null-reference operator is used in many java-based script languages, but is not a good solution for java language itself. The language always must be more stronger.
Posted by: nullpointer on January 16, 2007 at 03:26 AM
|