{"id":34,"date":"2007-12-09T13:41:16","date_gmt":"2007-12-09T12:41:16","guid":{"rendered":"http:\/\/www.bluej.org\/mrt\/?p=34"},"modified":"2020-05-15T15:46:27","modified_gmt":"2020-05-15T15:46:27","slug":"can-java-be-saved-from-death-by-feature-bloat","status":"publish","type":"post","link":"https:\/\/blogs.kcl.ac.uk\/proged\/2007\/12\/09\/can-java-be-saved-from-death-by-feature-bloat\/","title":{"rendered":"Can Java be saved from death by feature bloat?"},"content":{"rendered":"<p>We all agree that Java needs simplicity &#8211; we just don&#8217;t agree what that means.<\/p>\n<p>Several things came together recently that made me think about simplicity in the Java language again, and what that might mean. And one thing is clear: simplicity is not simple!<\/p>\n<p>Events that prompt me to write about this again were feedback I recently received about <a href=\"http:\/\/www.bluej.org\/mrt\/?p=31\">another blog entry<\/a> (where I discussed simplicity in more general terms), a discussion by the <a href=\"http:\/\/www.javaposse.com\/\">Java Posse<\/a> guys about new language features, and my own teaching. (First term is about to draw to a close in our parts of the world, so I&#8217;ve just been through 12 weeks of teaching another cohort of freshmen programming in Java again.)<\/p>\n<p>The executive summary is: I think many of the recent discussions for changes to Java are in danger of pulling the language downhill fast, and the term &#8220;Simplicity&#8221; has different meaning to different people that cause directly contradictory results for language design.<\/p>\n<p><!--more--><br \/>\nBut one step at a time.<\/p>\n<p>In <a href=\"http:\/\/www.javaposse.com\/index.php?post_id=281768\">episode #151<\/a> of their podcast, the Java Posse discussed a whole list of proposals for changes to the Java language (proposed for inclusion in Java 7). These include closures, certain instances of type inference, chained invocations, &#8220;extension methods&#8221;, and more. Most of the ones discussed in the podcast are <a href=\"http:\/\/docs.google.com\/View?docid=dxm5z6n_143hpcptw\">described in a document here<\/a>.<\/p>\n<p>Almost all of the changes were presented as making something simpler. Let&#8217;s look at an example, &#8220;<em>Extension methods<\/em>&#8220;.<\/p>\n<p>Extension methods are a mechanism where single static methods can be imported, and then called with a syntax similar to instance methods. The example presented in the document linked above is the following:<\/p>\n<blockquote><p>Extension methods<\/p>\n<p>Existing interfaces cannot be extended with additional methods without breaking some clients. Instead, functionality is typically &#8220;added to an interface&#8221; by static methods in a separate utility class. Using them is somewhat awkward:<\/p>\n<p><span style=\"font-family:monospace\">List list = &#8230;;<br \/>\nCollections.sort(list);<\/span><\/p>\n<p>With extension methods, client can designate utility methods to act as if they were members of the interface (or class)<\/p>\n<p><span style=\"font-family:monospace\">import static java.util.Collections.sort;<br \/>\nlist.sort();<\/span><\/p><\/blockquote>\n<p>Now, this feature is proposed to make it simpler to write a certain kind of method call. Most of the other proposed features are in similar spirit: they make writing something simpler that is somewhat awkward in the current syntax. <em>Chained invocations<\/em> simplify writing a certain sequence of method calls; <em>Constructor <\/em><em><a href=\"http:\/\/gafter.blogspot.com\/2007\/07\/constructor-type-inference.html\">type inference<\/a><\/em> saves typing a whole string of characters in certain constructor calls; <em>enum comparison<\/em> saves having to call .ordinal() before using comparison operators with enums, and so on.<\/p>\n<p>But here&#8217;s the catch: simpler for whom?<\/p>\n<p>The mindset of the argument here is that of the writer: it is simpler to write this new syntax than to write the current one. But this is a lazy sort of simplicity. I would argue that most of these changes make Java worse, because they make the language harder, not simpler.<\/p>\n<p>They make Java harder to read, harder to understand and harder to learn.<\/p>\n<p>Simplicity is not equal to simplicity. Simplicity for the writer can mean work for the reader. Putting an added burden on the writer can simplify things for a learner. Simplifying for the writer is the most counter-productive form of introducing simplicity.<\/p>\n<p>Like all writing, code should be carefully written to make the reading experience as good as possible. Not the writing experience. I really don&#8217;t care about saving a few characters typing if that means that the reader has to use more brain cells to work out what&#8217;s going on.<\/p>\n<p>They are really quite different meanings of simplicity.<\/p>\n<p>Take another example that has already happened: auto-boxing. Does auto-boxing make Java code simpler?<\/p>\n<p>In one meaning of the word it does. It is now simpler so write code that inserts primitives into collections. But does it make the language simpler? Hell, no!<\/p>\n<p>When I teach my students now, I have to explain a lot more. I have to explain the new mechanism (<em>list.add(3)<\/em>), and in the process of explaining it I explain about wrapper classes (<em>list.add(new Integer(3))<\/em>). If I don&#8217;t, there is a real danger that students draw wrong conclusions from the code (that primitives can be in collections, or that ints are objects).<\/p>\n<p>See, you can still not get away with pretending that ints can be added to lists. I see that every year when students try to write<\/p>\n<p style=\"text-indent:20pt\"><span style=\"font-family:monospace\">private List myList;<\/span><\/p>\n<p>That, of course, does not work. You have to write<\/p>\n<p style=\"text-indent:20pt\"><span style=\"font-family:monospace\">private List myList;<\/span><\/p>\n<p>even though you then proceed to apparently add ints to the list. In other words: To make sense of it all, you still have to understand the whole story, the primitive\/object distinction, the wrapping, <em>and<\/em> the auto-boxing.<\/p>\n<p>Compared to the Java 1.4 version without auto-boxing, that has made the story you need to learn more complicated, not easier. So what we have got is a gain in simplicity for the experienced writer, and a gain in complexity for the learner. The simplicity gain, however, is largely a saving of typing a few characters (with maybe a little bit of neater looking code) while the loss in understandability is a potential serious problem.<\/p>\n<p>The fact just is: for initial learning, auto-boxing is a step back, not forward.<\/p>\n<p>The same is true for almost all the improvements suggested now. They save typing for the experienced coder, so people who know what they are doing like many of them. They obfuscate, however, what is really going on underneath. Deeper understanding of more detailed language rules is required to correctly interpret the results, and the potential of error rises.<\/p>\n<p>And it rises exponentially!<\/p>\n<p>One problem with adding features to a language is that complexity does not rise in a linear fashion with every new feature, but language complexity is exponential. Because every feature can potentially interact with every other feature, the number of potential problems explodes.<\/p>\n<p>Take auto-boxing as an example again (since this is such a nice and simple example &#8211; it gets worse with some of the other features!). Consider the following statement:<\/p>\n<p style=\"text-indent:20pt\"><span style=\"font-family:monospace\">boolean result = !(i &lt; j) &amp;&amp; !(i &gt; j) &amp;&amp; !(i == j);<\/span><\/p>\n<p>Assume i and j are numbers. What we are saying in this expression is quite simple: i is not less than j, i is not greater than j, and i is not equal to j. Now the question: Can this ever be true?<\/p>\n<p>Take a moment to think about it.<\/p>\n<p>Going by our intuition (and everything we knew up to Java 1.4), the answer would be no. Since Java 5, however, it can be true. Here is how:<\/p>\n<p style=\"text-indent:20pt\"><span style=\"font-family:monospace\">Integer i = new Integer(13);<br \/>\nInteger j = new Integer(13);<br \/>\nboolean result = !(i &lt; j) &amp;&amp; !(i &gt; j) &amp;&amp; !(i == j);<\/span><\/p>\n<p>With this definition, <em>result<\/em> will be true. This is because the &lt; and &gt; operators auto-unbox, but the == operator does not and does object reference equality instead. It is counter-intuitive, completely useless for anything sensible in practice, and a potential for error.<\/p>\n<p>Now, this problem comes in only through the unexpected combination of apparently simple features. Auto-boxing is simple. The primitive\/object distinction is simple. Comparison operators are simple. But put them together, and you get something that looks like a trick question that even experts have to think about for a moment (and beginners just cannot explain by themselves).<\/p>\n<p>The real problem here is the interaction of features, combined with a deceivingly simple appearance that covers up more complex functionality.<\/p>\n<p>The problem with the proposed language extensions for Java is that most of them do the same. They introduce simple syntax for more complex functionality, and knowing simple rules is not enough for the reader anymore. The reader needs to understand the full complexity of the additional rules to correctly interpret the code.<\/p>\n<p>This is not how code should be written.<\/p>\n<p>When you write code, you should always assume that the reader (a future maintainer) is not as smart as you are. That is not because you are the most brilliant programmer around (although you might be). That future not-so-smart maintainer might even be yourself, just having a bad day, or having your brain already full with a complex problem you are working on.<\/p>\n<p>The fact of the matter is: making it easier to understand for someone a little slower on the uptake is always worth more than saving 20 seconds typing a few more characters.<\/p>\n<p>Now, some of you will say that the proposed language changes are not only about saving typing, they also make the code simpler to read. That is just not true. They make the code <em>appear<\/em> simpler, while actually making it harder. Simple code is code that does exactly what it appears to be doing. Simple code is not code that looks simple and then goes and does something different. Because there will be situations where you have to understand exactly what&#8217;s going on, and then having code that glosses over the details is not helping.<\/p>\n<p>Look at one very simple example of this convenience design: the rule that states that you are allowed to leave out the constructor call to superclasses for default constructors. In other words:<\/p>\n<p><span style=\"font-family:monospace\">class A extends B {<br \/>\n<\/span><\/p>\n<p style=\"text-indent:20pt;font-family:monospace\">public A() {<br \/>\n}<\/p>\n<p><span style=\"font-family:monospace\">}<\/span><\/p>\n<p>is automatically interpreted as<\/p>\n<p><span style=\"font-family:monospace\">class A extends B {<br \/>\n<\/span><\/p>\n<p style=\"text-indent:20pt;font-family:monospace\">public A() {<\/p>\n<p style=\"text-indent:40pt;font-family:monospace\">super();<\/p>\n<p style=\"text-indent:20pt;font-family:monospace\">}<\/p>\n<p><span style=\"font-family:monospace\">}<br \/>\n<\/span><br \/>\nNow, if B does not have a default constructor (a constructor without parameters), then the error message you get in the first version is completely cryptic. It highlights the signature of A() and says &#8220;cannot find symbol &#8211; constructor B()&#8221;. Every year I see students who struggle to interpret this message. The reason is that the error is caused by a call that is invisible.<\/p>\n<p>Convenience in not having to spell things out leads to problems in interpretation if you do not fully know the details of the rules.<\/p>\n<p>Now you may say that this is an example about beginners, and you are a developer with experience. I claim that this, in fact, does not make a difference in principle. Most programmers display beginner-like behaviour in some situations.<\/p>\n<p>When we start doing the same hidden-functionality-by-special-rule design with the proposed chained invocations, extension methods, type inference, and other such things, we are laying traps of misinterpretation, and someone will step into them. Worse, we are creating interactions with other constructs and start seeing odd behaviours that are hard to deal with.<\/p>\n<p>This is also the problem with otherwise very nice language extensions. The most talked about proposal for Java currently is the addition of <a href=\"http:\/\/gafter.blogspot.com\/2007\/10\/java-closures-first-prototype.html\">closures<\/a>. Now, <a href=\"http:\/\/www.javac.info\/\">closures<\/a> are a very nice idea, and I&#8217;d like to see them in a modern programming language. However, I am not convinced that retro-fitting them into Java is a good idea. Had they been properly designed in from the start, then, sure, go for it. But now we are constrained by all sorts of existing constructs that we cannot change without breaking the language, and will see strange interactions with these constructs. I think it&#8217;s a bad idea.<\/p>\n<p>If we wanted to make a new language, say NewJava, where we had the freedom to drop compatibility and change existing language features, then closures could be made to fit. But as it is, it has a Frankenstein feel to it.<\/p>\n<p>One of the problems with the whole discussion is that, by it&#8217;s very nature, the language evolution discussion is carried by people who understand the language well. If you already know all of Java, learning a new feature (such as closures) is quite manageable, even if we have to learn a number of spacial case rules for the weird interactions. For new learners it is quite different: every new language features bumps up the complexity of the language exponentially, and learning the language gets that much harder.<\/p>\n<p>That is what happened with genericity. For all of us who grew up with Java, adding genericity was a manageable step that we could concentrate on in isolation, because we already understood the rest of the language. New programmers today do not have this luxury: they have to deal with it from the start (you can just not ignore it, since it&#8217;s all over the class libraries), and that makes getting started with Java harder. Adding even more features will increase this effect.<\/p>\n<p>I am not sure what the solution is. I am tempted to say &#8220;Leave the language alone and make yourself a new one if you want different features&#8221;, but I know quite well that that&#8217;s not how it works. Java will evolve, and it will grow, and it will become more complex.<\/p>\n<p>Maybe the solution is just that every generation needs their own new programming language. That language then can grow up with them. It starts simple while you&#8217;re a novice, and gets more powerful when you progress.<\/p>\n<p>But I do know that I am not looking forward to teaching Java 7 if it includes many of the proposals currently floating around!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We all agree that Java needs simplicity &#8211; we just don&#8217;t agree what that means. Several things came together recently that made me think about simplicity in the Java language again, and what that might mean. And one thing is &hellip; <a href=\"https:\/\/blogs.kcl.ac.uk\/proged\/2007\/12\/09\/can-java-be-saved-from-death-by-feature-bloat\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":179,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[63],"class_list":["post-34","post","type-post","status-publish","format-standard","hentry","category-java","tag-java"],"_links":{"self":[{"href":"https:\/\/blogs.kcl.ac.uk\/proged\/wp-json\/wp\/v2\/posts\/34","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.kcl.ac.uk\/proged\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.kcl.ac.uk\/proged\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.kcl.ac.uk\/proged\/wp-json\/wp\/v2\/users\/179"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.kcl.ac.uk\/proged\/wp-json\/wp\/v2\/comments?post=34"}],"version-history":[{"count":1,"href":"https:\/\/blogs.kcl.ac.uk\/proged\/wp-json\/wp\/v2\/posts\/34\/revisions"}],"predecessor-version":[{"id":1053,"href":"https:\/\/blogs.kcl.ac.uk\/proged\/wp-json\/wp\/v2\/posts\/34\/revisions\/1053"}],"wp:attachment":[{"href":"https:\/\/blogs.kcl.ac.uk\/proged\/wp-json\/wp\/v2\/media?parent=34"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.kcl.ac.uk\/proged\/wp-json\/wp\/v2\/categories?post=34"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.kcl.ac.uk\/proged\/wp-json\/wp\/v2\/tags?post=34"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}