That is the question. With my computer science course coming to end soon, I’ve been thinking about programming languages a lot. We’ve been using Java exclusively for this course and personally I don’t really like Java that much. My favorite language for application programming is Python, while for learning about computer science in general Scheme is my top choice. One of the things that I’ve been thinking about over and over during the semester is Java’s object orientation and type system, both of which I have mixed feelings about.
Let’s start with object orientation: As every computer science student knows, an object is a combination of data and methods to manipulate that data. That’s a very good way to model the interactions in a computer program and when used and implemented properly it is a very powerful tool. However what most students don’t realize is that object orientation is often one layer of complexity too many. There are often situations where you just need a simple function to perform some sort of manipulation on numerous data inputs. There is little data actually associated with the function itself, most of it comes from outside, and so forcing into an object-oriented methodology is clunky and inefficient. But Java doesn’t let you have free standing functions: functions aren’t first class citizens. This leads to some interesting workarounds. You have to create a wrapper class obviously, but after that things get interesting because Java has static methods. Unlike normal methods (for which every object of a class gets a copy), there’s only one copy of a static method which all the objects share. This makes sense conceptually, somewhat. If you have a sort method, you don’t need multiple copies of the sort method, you just want one method through which you can pass whatever it is that you want sorted. However it’s still tied to a class somewhere, which means that something is still “owning” that function (which doesn’t quite make sense). This is perhaps my biggest gripe about so-called “pure” object-orientation: there are some things that don’t conform well to the object-oriented ideology (and the other end is pure functional programming, but that’s a topic for another post).
So Java doesn’t have allow functions as first class citizens. I would like Java more if its object orientation was completely uniform, but it’s not. Not everything is Java is object-based. Java’s system for data types is a mix of objects, primitive types and arrays, each with its own different style. You can’t subclass either primitives or arrays. Primitives aren’t objects (I guess thats why they’re called primitives) and arrays are objects without classes. It’s something of a mess. This can lead to problems later on when you try to work with the various data structures that make up the Java Collections Framework. You can’t use the primitives as part of a collection, you have to use its corresponding wrapper class. That isn’t really a problem per se, but it’s one more thing to remember. By and large I do like the Java Collections Framework and the Java generics, though on occasion it can make code hard to read due to the smattering of angle brackets it entails.
However one aspect of the Framework that does irritate me from time to time is Iterators. To access the elements of a collection in order, each collection class must have an embedded Iterator class. To iterate over the elements of the collection, you have to create an instance of the iterator class and then use that. I personally would have liked to see iteration methods built into the collection classes themselves, but that is not something that is going to happen. Truth be told, iterators do get the job done. At the basic level they let you move forward over the collection and delete elements on the way. I personally try to avoid the use of separate iterators, I prefer using the “smart” for loop. This version of the for loop is similar to what Python has, it creates an object of whatever type the collection objects are and then uses that to access each object in turn. Unfortunately, the smart for loop fails to give you full access to the underlying iterator. I ran into this during my last exam when I tried to use a smart for loop to deletions to a TreeSet while moving through it. I couldn’t, and while I understand the technically difficulty, I know enough to know that it would have been possible and would have made the smart for much more useful. It wouldn’t have worked for plain arrays though because arrays don’t have underlying iterators.
So what has Java taught me about object orientation? Firstly, one size never fits all. Object orientation isn’t the perfect model for software development and it’s important to give programmers a choice, in this case: first class functions. Secondly, consistency is important. One of the reasons that C++ is gradually falling from grace as a language for large system development is its very inconsistent syntax, especially when you start doing more advanced programming. While Java is much more comfortable than C++, there are enough inconsistencies to make it occasionally hard to use. However all things said, both Java and object orientation are powerful tools for software development and its important to learn them both well, but also to realize that in certain circumstances there are more suitable tools.