We all agree that Java needs simplicity – we just don’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 clear: simplicity is not simple!
Events that prompt me to write about this again were feedback I recently received about another blog entry (where I discussed simplicity in more general terms), a discussion by the Java Posse 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’ve just been through 12 weeks of teaching another cohort of freshmen programming in Java again.)
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 “Simplicity” has different meaning to different people that cause directly contradictory results for language design.
But one step at a time.
In episode #151 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, “extension methods”, and more. Most of the ones discussed in the podcast are described in a document here.
Almost all of the changes were presented as making something simpler. Let’s look at an example, “Extension methods“.
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:
Extension methods
Existing interfaces cannot be extended with additional methods without breaking some clients. Instead, functionality is typically “added to an interface” by static methods in a separate utility class. Using them is somewhat awkward:
List list = …;
Collections.sort(list);With extension methods, client can designate utility methods to act as if they were members of the interface (or class)
import static java.util.Collections.sort;
list.sort();
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. Chained invocations simplify writing a certain sequence of method calls; Constructor type inference saves typing a whole string of characters in certain constructor calls; enum comparison saves having to call .ordinal() before using comparison operators with enums, and so on.
But here’s the catch: simpler for whom?
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.
They make Java harder to read, harder to understand and harder to learn.
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.
Like all writing, code should be carefully written to make the reading experience as good as possible. Not the writing experience. I really don’t care about saving a few characters typing if that means that the reader has to use more brain cells to work out what’s going on.
They are really quite different meanings of simplicity.
Take another example that has already happened: auto-boxing. Does auto-boxing make Java code simpler?
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!
When I teach my students now, I have to explain a lot more. I have to explain the new mechanism (list.add(3)), and in the process of explaining it I explain about wrapper classes (list.add(new Integer(3))). If I don’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).
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
private List myList;
That, of course, does not work. You have to write
private List myList;
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, and the auto-boxing.
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.
The fact just is: for initial learning, auto-boxing is a step back, not forward.
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.
And it rises exponentially!
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.
Take auto-boxing as an example again (since this is such a nice and simple example – it gets worse with some of the other features!). Consider the following statement:
boolean result = !(i < j) && !(i > j) && !(i == j);
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?
Take a moment to think about it.
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:
Integer i = new Integer(13);
Integer j = new Integer(13);
boolean result = !(i < j) && !(i > j) && !(i == j);
With this definition, result will be true. This is because the < and > 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.
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).
The real problem here is the interaction of features, combined with a deceivingly simple appearance that covers up more complex functionality.
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.
This is not how code should be written.
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.
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.
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 appear 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’s going on, and then having code that glosses over the details is not helping.
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:
class A extends B {
public A() {
}
}
is automatically interpreted as
class A extends B {
public A() {
super();
}
}
Now, 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 “cannot find symbol – constructor B()”. 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.
Convenience in not having to spell things out leads to problems in interpretation if you do not fully know the details of the rules.
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.
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.
This is also the problem with otherwise very nice language extensions. The most talked about proposal for Java currently is the addition of closures. Now, closures are a very nice idea, and I’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’s a bad idea.
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.
One of the problems with the whole discussion is that, by it’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.
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’s all over the class libraries), and that makes getting started with Java harder. Adding even more features will increase this effect.
I am not sure what the solution is. I am tempted to say “Leave the language alone and make yourself a new one if you want different features”, but I know quite well that that’s not how it works. Java will evolve, and it will grow, and it will become more complex.
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’re a novice, and gets more powerful when you progress.
But I do know that I am not looking forward to teaching Java 7 if it includes many of the proposals currently floating around!
The growing complexity is indeed a problem but you should see that other “static” languages have a similar problem. Take C++, it grew so horribly that the new proposals on it seem to make it better in several situations – but the complexity in fact INREASES!
Preach on man about autoboxing… it is offensive and even worse makes it really hard to teach it. I think that Java should not be in a race with c# to stuff newest and most junk into their language. But it is.
I agree with most of your points but I think your academic perspective may slightly distort the severity of the problem.
The reality is that your students learn the formal specs of the language and as soon as they pass the exam they forget it unless they continue to work with it. So it doesn’t matter what language specification you teach them. And lets face it: Computer language specs _are_ hard to grasp, especially for newcomers, and a few percent extra hardness don’t matter.
I myself was rushed through a Java course when I studied a few years ago. I knew it before so I didn’t find it hard. But what struck me was that the method of teaching was completely and fundamentally broken. Cramming everything into one semester, from bytecode up to Swing event handling, is simply _not_ the way to do it. So, please, please, _please_, teach your students what’s necessary to get going. Advanced wildcard generics? Leave them out. Transient and volatile? Leave them out. All those difficult inheritance border cases they make you analyze in a SCJP test? Leave them out. Closures, extension methods, all those fads if they should ever make it into the language, leave them out. That stuff doesn’t matter at all. Instead focus on: OO thinking, error handling, separation of concerns, well-structured code and where to find more information. Don’t teach them how to fish but to understand the sea.
And if they don’t get it: Please stop them from becoming programmers.
You raise some interesting points. I can see how additional features meant to increase working simplicity could certainly contribute to learning complexity, and how such gains would probably not be worth the effort.
From a personal perspective, I was taught Java for two years before coming to Kent, and although there were things which were taught differently, and things which I had previously not been taught at all, things like Integer boxing seemed perfectly logical and easy to grasp to me. Perhaps this is because I have had so long to get to grips with this, perhaps it is your excellent tutelage, or perhaps I just have the right mind for it. (Or, most likely, a combination of the three.)
I suppose what I’m getting at is that maybe if people were given a lot more time to learn a language, with carefully selected scenarios in order to avoid things like Integer boxing at first, they may be able to get to grips with it a lot faster. Of course, this really isn’t practical in most cases, other than bringing programming languages into colleges and schools a lot more than they are now. My college was one of very few in the country to teach Java, and I was so glad it did!
I suppose, in the end, stretching the learning process of languages like Java is simply an alternative to reducing complexity, and probably not an optimal one, either. Complexity can only be avoided for so long, and having things withheld from you as a student can be frustrating – especially if you have the enthusiasm to try out some code which hasn’t been set as part of an assignment. Keeping the teaching short probably prevents that enthusiasm from disappearing, since everything happens so quickly.
So ultimately, it might be a choice of simplicity and good, enthusiastic coders, or a lack of simplicity and good OR enthusiastic coders.
(This probably made no sense, as I really haven’t been sleeping enough lately. Darn you, assignment 3!)
It is amazing how much evil has been done in the service of “saving the programmer some keystrokes.”
“Hi, I’m from the language standards committee, and I’m here to help you…” 🙂
I agree with most of your sentiments (e.g. use-site extension methods probably shouldn’t be considered just yet), but I see some glaring errors in your reasons.
First off, readability has nothing to do with teachability. Java is a notoriously stupid language to use as a teaching tool. The fact that so many schools out there are using java for introductory CS is just an indicator of gross incompetence amongst colleges and universities. “Hello, World!” in java contains at least 8 separate concepts compared to the 2 in e.g. python or basic. Auto-boxing makes code easier to read. I know – I’m programming in java 1.4 notation for a few GWT projects (which is still limited to 1.4 syntax, though the imminent GWT 1.5 will finally bring java5 syntax to the platform). The readability of my server side code compared to my client side code cannot be compared, really. The differences are that big.
What it usually boils down to is this: Take your code. split it up into mental atomic compartments. Each operation is 1 atomic thing for your brain to understand. Rate each atomic thing according to how hard it is to grok (this is a fluid thing and depends on its context). Now you have some indication of how hard your code is, for reading. list.add(3) is one atomic unit. list.add(Integer.valueOf(3)) is two. The ‘weight’ of each unit is somewhat less for the second example (which is what you were driving at, I think), however, as we need to take context into account, the exact amount of complexity added by “list.add(3)” depends. However, in the -vast- majority of circumstances, it just doesn’t add anything you’d ever need to know about. It’s annoying as a code reader that you need to be aware of those situations where it might be an issue, but in the end we live in the real world, and unreadable code can be written in any language, no matter how hard you try to avoid it as a language designer.
Let’s go back to use-site extension for a moment. The complexity factors are somewhat detailed and I won’t delve too deep in, but to give a taste:
– multiple inheritance: What if 2 interfaces each contain the same method, both implemented by the same class?
– runtime vs. write time discrepancy. What if at compile time/call time the given class inherits a static mixin method from one of its interfaces, but during runtime you actually get something else, a subclass, which overrode that mixin? What method gets called? Or, what if the interface class file is recompiled later and adds a mixin. How will that affect things?
These are good reasons for use-site extension to require a little more thinkthrough. Code complexity for the common case, however, isn’t. Take the following code snippet:
“list.sort();”
what’s this do? I sure hope it sorts the list. If it doesn’t, the code is broken. The fact that the original List interface never defined a sort, and that thus we are stuck with “Collections.sort(list);” in java, makes not one iota of difference. If you want to write code that doesn’t sort a list when you write “list.sort();”, you can, and no amount of safeties put in on the language level will stop you from being an idiot. In the end, this common use case of adding mixins doesn’t complicate things in the least, especially if you consider IDEs. For at least some specifics of the various use-site extensions proposals, the IDE/compiler knows exactly which static method is ‘secretly’ being called. The IDE can therefore send you to the right place if you ctrl/cmd+click on the identifier (‘go to definition’ in most IDEs), and can even render the call in a special fashion (such as e.g. italics, which is already used as a static member marker in some IDEs) so that you are actively aware it’s just sugar.
Not being able to resolve corner cases efficiently is good enough reason for me to hold off, at least for a while. The location of the use-site extension code is probably best placed at the project level, but java the language doesn’t really have such a beast yet. Maybe superpackages will give it to us, in which case I might support it for java 1.8. We’ll see. However, if the corner cases didn’t exist, I’d say: Yes, by all means, give me use-site extension methods, because it DOES make code more readable. In the vast majority of situations, the implementation detail that list.sort() is being done by a mixin is just not relevant.
It’s just like inherited methods: You can’t tell from a mere glance that a method you’re calling is implemented by the class itself, or by a superclass, or if the class is aware but shelling out its implementation elsewhere via a wrapper function. And yet, we have that now. It’s part of java, and it’s not going away anytime soon. mixins/use-site extensions are actually nicer in many ways; unlike with non-static methods, you know exactly where that code is coming from. In the rare case its important, your IDE can point you to it immediately.
Thanks for making an excellent point.
Let me add to it by raising a more general question. Is there some point in the evolution of a language that language designers will say “thats it, we are done with this language for now”.
When a language starts out as new, the designers obviously have a lot of work to do. Catch up with the needs that the language sought to fulfill and match features that similar languages provide. But, there has to be some point where those needs will end or at least become so less that you don’t need so many designers working on it. But still the language continues to grow; is it because the growth serves some valid purpose or because there are so many people around whose jobs are to improve the language.
Is it OK for a language to hit a plateau?
Or does it have to go through a life cycle where it will eventually die and something else will then come up to fill its place?
I think the language designers can influence this choice. You need a different set of people “managing” a language than “creating” it.
What say you.
PS: And for a love of GOD don’t add syntactic sugar because it makes it “easy” for someone to write code. There are already enough abstractions in Java that make it hard to keep in perspective what goes beneath it, lest we forget that a programming language is huge lie that programmers are allowed to live as long as the complier/interpretor can cover up for us.
Scala is the NewJava. 🙂
Can’t agree with you more 🙂
Why is C language is still beeing used? The answer is simplicity!
K.I.S.S. = Keep It Simple Stupid! 😉
The problem with many of the new Java features is that the design apparently attempts to make programming easier by glossing over some syntax, but not by fixing the underlying inconsistencies in the language.
Auto-boxing, for example, really does make things easier if you change the language to the point that the need to “box” or “unbox” is merely an implementation and performance issue that doesn’t affect language semantics. That could be accomplished by changing the meaning of ‘==’, disallowing nulls for some object references, and defining ‘int’ as an alias for Integer. Not too big a change in the grand scheme of things (and in fact, would probably have several other benefits), but of course it would blow away backward compatibility, so it won’t ever happen. Adding auto-boxing in a way that’s observable in language semantics is a problem.
Similar things can be observed with generics. Some of their complexity is inevitable; but other parts of it would just completely go away in the absence of type erasure, a construct invented for backward compatibility — but which in practice just makes it near impossible to write warning-free code without using @SuppressWarnings.
So it’s not that the ideas are bad; it’s their being incompletely carried out that causes many of the problems.
You can’t argue against including closures by pointing out how stupidly Sun has implemented past “features”. That’s a strawman. The fact that the autoboxing and generics implementations are affronts to all things good and decent in the world has nothing to do with a completely unrelated feature, unless you are making the case that the people with commit access are just incapable of integrating new features well.
And seriously – why the hell are you using Java to teach new programmers? The real problem that this post illustrates is how ridiculous computer science education is. Java is not a good teaching language, period, because it is (somewhat poorly) designed for medium-skilled professional programmers who need to solve real-world problems, and as you point out, it keeps accumulating cruft from the desire to introduce new features without breaking compatibility with previous bad design decisions. It’s too high-level for teaching how computers work, where C might be appropriate, and it’s too low-level to be expressive enough to demonstrate many CS concepts clearly and concisely.
In the classroom, use Scheme, Python, Ruby, or even Javascript. If you think static typing is important, then use Haskell or even Scala (if we’re talking about beginning programmers, you shouldn’t have to worry about the overhead of switching to a functional mindset).
I’d argue that Scala is especially exemplary of what a statically-typed language like Java *could* be. Despite having functional elements, Scala is probably best described as an agnostic language: it blends imperative OOP with functional concepts. And it does it *nicely*, resulting in a language that’s both elegant and powerful, not at all like the monster Java is looking to become in JDK7.
I’d have to reiterate Jason’s comment: If Java is so bad, why are you still using it for teaching?
And just because features exist in Java, that doesn’t mean you should teach it in a CS course. CS is about learning how languages work generally, not Java specifically. If students are taught how languages work, then they should be able to read the documentation for and pick up and use (almost) any feature of (almost) any language that they want to.
And is it really so wrong that people learn that you can’t use primitives by trial and error? I don’t know about others, but that’s the way I’ve learned about lots of language quirks for various languages. It’s not like there’s no one there to teach them why they can’t do that when they do try to do it – these students have a university and an Internet of resources to help them!
Stop trying to teach Java. Start trying to teach languages.
Very insightful article. It’s true: we should go back to basic.
So given a trade-off between teachability and clarity for experienced programmers, you choose teachability? This seems backward to me: why optimize a language for a group of people who will only be in the group a short time?
Nice article.
I’d have to say that looking at Java *solely* from a learnability perspective would lead it to being another Pascal, i.e. little in the standard and lots of non-standard extensions that are required to get any work done in the real world.
On the other hand, looking at Java solely from an ease of coding perspective will lead to Java being the next C++ — so many weird nuanced features and rules that few mortals can keep them all straight. Or the next Perl — so many odd illegible ways of doing things no mortal can read it.
The key is balanced consideration of learnability, ease/power of coding, and readability/maintainability. Given that most of code’s expense and lifecycle is maintenance, it is important not to give short shrift to the last of these items.
Many of the proposals consider only ease/power of coding — and in that they’re dead wrong.
Others assume a strict organizational code review process where abuse of a language feature is vetoed (e.g. Google clearly has this and their language features seem to assume this) — and in that they’re wrong, most organizations don’t have this and features prone to abuse should not be added assuming such a process. The language could require a Java compiler have means of disabling some features, of course… Though that leads to language dialects — better just not to have the feature in question.
No offense to Reinier, but: (1) I see Java as a much better language for learning programming than many I was taught in [Fortran, Pascal, C,…] and (2) use-site extensions are *evil* — they imply that the reader should look for “sort” on the class of list or a superclass thereof. When that’s not the case, the reader is justifiably flumoxed. The reality is that there is a separate Collections utility class and the code should reflect reality, not some make believe world that will just confuse those trying to understand it later.
I am in fact one of the Students that is mentioned within the original post. And I agree with one of the comments. I have found that by focusing on fundamentals which then enable us to discover the more complex features is far more important, and is something that I feel is done very well by Michael Kolling.
I was not a novice programmer, but I was new to Java, but instantly noticed that the fundamentals were the same as those I had previously learned. There is no point adding features to a language, when the grass roots of the language make it impossible to grasp.
Sense and Simplicity as Philips would say. And it is something that is dying out lately as things become inherently more complex for no obvious reason.
I have to agree with Chris and Jason. The backwards compatibility demand means that the language cannot be refactored into a better design, which leads to evolution by duct tape. Whether or not the extension of a bad language by duct tape is a good idea is certainly up for debate, but it seems to me that it’s not a very important thing to debate.
Personally, I’m not too worried about the extra ugliness of closures. For me, it’s a difference between an ugly, bloated language and an ugly, bloated language with closures. I’d rather just use a nice language, but if I have to use an ugly one then it might as well have closures. Simplicity is a lost cause with Java.
Pingback: Michael’s Random Thoughts » In Defense of Java
Pingback: Labnotes » Rounded Corners - 171 (Sex it up)
Pingback: Code Vault » Blog Archive » Interesting “bloated java” Article
Pingback: Hypothetical Labs » Java’s Doom Spiral?
Michael: I pretty much agree with any single point, the only thing I miss in your writing is the point that there are some simplifications that benefit everyone, most noticably the removal of cruft: currently Java has four distinct type systems (objects, primitives, references, arrays) and some are broken (mutable String[]s are not Object[]s, and instanceof lies about null, which is really an instance of the absurd type of the references). Cleaning that mess up would help everyone.
Then there are features that make the language more expressive. They tend to hurt the beginner, but they make life easier for both writer and reader once they are accustomed to them. One example of that would be pre- and postconditions IMO. The beginner will find them hard to understand (although they might be able to get away without doing so for a while), but an experienced writer will appreciate being able to say what they mean and the experienced reader will appreciate a unified language instead of messy JavaDoc or having to go into a libraries source to understand what’s going on. And both writer and reader would benefit from the compiler taking away some of the checks they would otherwise do.
So I think you are right with your post, including the hope for a NewJava. But I also think that there could be some things that truly improve Java, it’s just that Autoboxing wasn’t one, Generics didn’t really work (although I think overall it’s a plus, albeit painful in itself) and the currently discussed ones don’t seem to be any good either.
That’s my 2c 🙂
We all enjoy nitpicks, don’t we?
If i and j are two numbers, your statement can also be true without boxing:
double i = Double.NaN;
double j = Double.NaN;
System.out.println(!(i j) && !(i == j));
Which is of course nitpicking, but it does also make a point. This stuff is a lot more complicated than we use to think. Every programming language I know has these dark corners, and teaching them to people is difficult.
Ugh. Not to forget the whole escaping/unescaping mess that people get wrong oh so often…
double i = Double.NaN;
double j = Double.NaN;
System.out.println(!(i < j) && !(i > j) && !(i == j));
+1 for Scala being the next Java.
This post is just human nature. There’s always a bunch of old codgers complaining about change. The only thing that Java is really at risk from is all the old codgers.
I just realized that you didn’t include one of the things that make your example with the comparison operators even more nasty — you might have skipped that on purpose, but maybe you haven’t heard it yet, so I might add it here:
If your two Integer instances with the number 13 are actually coming from Integer.valueOf(int), then they will actually be the same (at least with a Sun JDK). Integer.valueOf(int) for some reason caches the signed byte range, so any value between -128 and +127 will return the same instance of Integer every time.
The fun thing is that autoboxing calls that method, i.e. if you do “Integer i = 13;” you will get the same instance every time, so the equality test works. But only if you sticked with the signed byte range. And maybe not if you use other JDKs.
Fun, isn’t it?
Actually, I think Java is quite a good language to start with. Object orientation!
I personally had a great first term doing CO320 (that’s mik’s Object Orientation course at Kent) and I don’t believe we were really just being taught about Java like it has been implied.
We’ve done OO, testing, design, style. Java constructs were only the surface.
We who are not happy with new Java can fork the standard and maybe the implementation and keep *our* Java simple. (I propose ‘kiss_java’ file extension. 🙂 )