Why Michael Schwern is not a Java programmer

by Simon Cozens

Before I begin, I must make a clarification. This is an article about
why I am not a Java programmer, one person's reasons and thoughts.
It's not about why you are not a Java programmer and it's not about
why Perl is better than Java. It is also not about why Java is the
way it is, I (mostly) understand Sun's design decisions in doing
things the way they've done them. But knowing why something is the
way it is doesn't make it any less irritating. [1]


Please keep this firmly in mind while reading.


Recently, I moved back to Pittsburgh after a stay in New York City for
a few years. [2] In NYC, Perl jobs are plentiful and Perl is fairly
well respected as a language to get things done. In Pittsburgh,
``Perl'' is a four-letter word while ``Java'' is not. I'm reminded of
this all the time. Since I've been gone, most of my programming
friends have switched to Java, even the people who taught me Perl.
``When are you going to learn a real language?'' I'm asked, and it's
long past being funny. I've gotten tired of parrying the same old
critiques.


All this crystallized for me when a friend of mine, during yet another
Java vs Perl argument, asked me ``What is Java missing?'' This was not
really my thinking at the time, I'm not as concerned with what a
language has as to how it goes about it. Few modern languages are
``missing'' any really critical features, it's more a matter of how
easily they can be expressed. However, this does let my brain start
organizing my objections.


I'll try to avoid incidental things. I won't complain about the way
Java looks or refer to the mythical ``typical Java programmer'', just as
I'd expect not to hear about Perl's ``line noise'' and stupid things your
CGI programmer friend did. I'm not going to get into closed source vs
free software, or which one is faster, or one supports some protocol
that the other doesn't... all this could change tomorrow.


Instead, I'm going to stick to purely technical arguments about
design decisions in the language. I feel these are fundamental design
decisions which aren't going to change anytime soon in Java, that
I can't easily work around and would really get in my way. [3]


Without further ado, some reasons why I program in Perl instead of
Java.



``Hello World'' should be one statement


Yes, I dredged up this old argument. Before your eyes glaze over,
hear me out. This isn't the cheesy, old argument about which one is
shorter.


Here's ``Hello World'' in Perl.



print "Hello, world\n";

One line, one function, one string. What does it do? It prints
``Hello, World''. Explaining it is almost as simple as writing it.
The trickiest part is possibly the newline.


And here in Java.



public class HelloWorld {
public static void main (String[] args) {
System.out.println("Hello, world!");
}
}

This basic of all programs drags in the concepts of class, privacy,
types, methods, the magic ``main'' method, the String class, arrays,
class methods vs object methods and chained method calls. And on top
of all that it, it has to be saved in a file called ``HelloWorld.java''.
One must know all this (or cut & code it) just to get moving.


This makes it difficult to teach Java to a first-time programmer.
Just to get off the ground, you've got to get past the whole OO
philosophy. What's a class? What's a method? What's privacy? Why
does it need to be called main? What's String[] mean? What's void?
Why is it System.out.println? All this incidental crap is exposed to
the student, someone who's still struggling with the idea of a text
editor (``What do you mean I can't program in Word??'') You can, of
course, hand-wave all this, but that doesn't settle well with me at
all. I prefer to use as little magic as possible when teaching.


I recently had the pleasure (?) of teaching Perl to a 14-year-old. I
started with ``Hello, World'' ('This is how you print something and run
a program'), moved onto conditional logic ('This is how you print
something if something else happens') and then to loops ('This is how
you print something a bunch of times'), etc. Each lesson contained
only one or two new concepts. Each concept produced a concrete
result. Each new lesson built off the last. All with a minimum of
hand-waving.


Nit picking? Possibly, but it is a symptom of deeper problems. To do
anything in Java, even simple things, you've got to roll out all these
conceptual cannons. You can't do one-liners in Java (assuming a
sufficiently short line). The upshot of that is if you know Java
you'll have to learn another language for quick tasks. For some, this
isn't a problem, but I'm lazy. I like having one language which
handles the vast majority of my daily tasks.



There's more to life than OO


OO is currently vogue. Someday it will not be. Can Java adapt? I
know Perl can, it demonstrated its flexibility when it made the leap
from structured to object-oriented programming six years ago.


Because Java is selling you a philosophy of programming, anything
which does not fit into that philosophy rapidly becomes awkward. This
is typified by ``Hello, World''. It is not a data-centric task,
therefore the OO solution is clunky.


There's nothing you can't do with objects. There's nothing you
can't do with any Turing Complete language. But that's not the
point. The point is how easily, elegant and maintainable can you do
it? When you try to shoehorn every programming task into one style,
things get ugly. I'd rather have a tool-box full of lots of different
tools than one with 57 kinds of hammers.


And what of other styles? Structured programming has not breathed its
last, and functional programming is just coming into its own, just to
mention two alternatives. I've recently started playing with
object-inheritance in Perl and find it useful. Can a strict,
class-based OO language be adapted to new styles or will they become
the COBOLers of the future? I know Perl can adapt.



No source for core classes and utilities


I wrote a quick Perl program to automate a set of remote benchmarks
(ironically, they were benchmarks for a Java program). Very quick:
log in, run a few commands, log out. Unfortunately, Net::Telnet had
some built-in assumptions about what a password prompt should look
like that this system didn't follow. After peeking at the source I
found the problem, but there was no clean way to change the behavior,
I'd have to override the whole login method. So, I wrote a quick
subclass by copying the 160 line login routine from Net::Telnet and
modifying the password regex. Cut and code at its finest, but it got
the job done.


I caught some ribbing from my friend about this, ``Such a powerful,
concise language Perl. It only took 160 lines!'' However, could I
have done this in Java? No. Why? No source code for its core
classes! Faced with a similar situation (Java doesn't prevent bad OO
design), a Java programmer would have either had to find an alternate
telnet class to use, or rewrite the entire login routine. Finding the
problem would have also been harder, lacking the ability to step
through the login() routine in a debugger to pinpoint the failure.


My solution was messy, but it was a messy problem. Perl kept a hard
thing possible.



No CPAN


CPAN is half the power of Perl (along with five or six other things).
Having a single repository of Free [4] high-quality, well-documented
and well-tested software (for the most part) with a common test and
installation suite. The ability to need code to do X, finding it in
one place, knowing it's probably going to be something more than Joe
Hacker's little one off (not to say CPAN doesn't have its share of
those) and not having to worry about license fees, can slash
development times drastically.


Java, and most every language, lacks this vital, centralized resource.[5]
There will typically be several equally popular repositories, varying
in quality and openness (ie. Microsoft might provide a lot of Java
classes, but what's the license like?) supplemented by smaller
repositories and individuals. What you need is out there, but how
hard is it to find it, know you've found it when you see it and use it
once you've got it? And how much will you have to pay for it?



No function pointers means no closures


Not having function pointers in an all-OO language isn't in itself so
bad, since a similar effect can be had by passing in the name of a
method along with a class or object. The real problem is that without
function pointers you cannot have closures. No closures makes lazy
evaluation, and other parts of functional programming, difficult.


Some of what closures do can be simulated with inner and anonymous
classes, but their conciseness is lost.


A closure can be thought of as OO inside out. Instead of data with
code attached, it's code with data attached. Is this OO? Sure! In
fact, several of Perl's OO systems have been implemented using
closures [6]. It's a different approach to the same problem, and it's
good to have lots of tools in your tool-box.



No symbol table manipulation


99% of the time, mucking with the symbol table is wrong. And most
programmers will get by just fine without ever even being aware of its
existence. The Devil is in that last 1%. When, damn-it, you just
really need to generate a whole bunch of variables and to do it any
other way would require hours more work.


This is what I call a 1% feature. 99% of the time, it's not needed by
99% of the people, but for that last 1% it can really make life a lot
easier.


Often, symbol table spelunking allows very surprising code libraries
with interesting and unexpected effects. Language designers can't
anticipate everything, and it's often good to be able to take a
language in a totally unexpected direction. Symbol table manipulation
is one that allows this sort of hackery.


Of course, this feature is very often abused, most of the time things
are much better accomplished by better data structures. However,
abuse by novices does not mean it should be denied to everyone. The
impact of such odd features can be lessened by properly structuring
documentation and books to deemphasize such 1% features. A Perl
tutorial shouldn't even bring up symbol table hacking (alas, many do).


Is symbol table hacking nasty? Yes. Is it messy? Yes. Should it be
avoided when possible? Yes. But remember, any sufficiently
encapsulated hack is no longer a hack. [7]


Much more tragically for an OO language is that a closed symbol table
means...



No dynamic method generation


Every OO programmer reaches the point in their understanding when they
grok encapsulation. I mean truly realize the benefits of wrapping
everything up in methods. The class is thy sword, and the accessor
method is thy shield and micro-optimizations be damned!


Roughly five minutes later you never want to see another accessor
again.


Computers are basically well-trained monkeys, and your typical
accessor is monkey code. getName() returns a name. setName() sets
the name. getAddress() returns an address. setAddress() sets an
address. Repeat until carpal tunnel. Let the computer handle this
busy-work for you! Not only is it lazier, but it's easier to maintain.
Basic laziness tells us that if you have twenty methods which all
basically do the same thing, you should consolidate them into one
method. A single point of change.


Perl has lots and lots of ways to do this. Class::Struct (distributed
with Perl) and Class::Class to name two. This is so important that I
wrote one myself, Class::Accessor. 60 lines of code, 5 methods.
Fairly simple both inside and out.


All rely on one or more of function references, eval and symbol table
hacking to generate methods on the fly. Alas, there's no easy way to
do any of this in Java.


Ah ha! What about writing generic get() and set() methods?
obj.get('Name'); obj.set('Address', '32 Yarrow Way'); The problem
with this approach is three-fold.


First, inheritance is defeated. If I wish to alter the way
obj.getName() works, I can simply override it. To change how
obj.get('Name') behaves get() must be overridden and with that all
the parameter's behaviors must be taken into account. Encapsulation
is blown.


Second, you tend to wind up with a big hairy case statement.
Polymorphism helps break it down somewhat, but you still wind up
handling multiple fields in a single method.


Third, the issue of how to get the types right. You wind up abusing
polymorphism, each group of types must be handled by a separate
polymorphic method, scattering the accessor code around and defeating
the purpose of writing ``single'' get() and set() methods.


What about using editor macros to generate the accessor code? Problem
there is the next person to maintain your code won't have your editor
or your macros. Count on it. [8]


Preprocessors. C uses a preprocessor to get its work done, why not
Java? When C came about, preprocessors were a good idea. Then again,
so was paper tape readers and pet rocks. The problems with
preprocessors are so well documented that it's probably redundant to go
over them here, but history is often forgotten. They make debugging a
pain in the ass [9], when your source code doesn't match the running
code.



No eval


eval is another one of those 1% features. The ability to add new code
to a program while it's running is a colossal amount of power. I
actually find eval to be a messy solution and usually find a better
way, but they usually involve other techniques Java can't do (closures
and symbol table mucking).


Unfortunately, a free form eval in Java would violate all sorts of
compile-time checks, so it's not going to happen. You can create
and load new classes on the fly (simply write a class file to disk and
call javac) but it's not quite the same as being able to alter an
existing class to fit. And what are the odds the user of your program
has Java compiler installed? Pretty slim.


It's odd that an interpreted language (yes, Java is interpreted. A
virtual machine is just a fancy name for an interpreter) would fail to
have some way of eval'ing new code. [10] With no eval, the whole idea
of dynamically-generated and self-altering code becomes very
difficult, if not impossible.



No multiple inheritance


A lot of people knock multiple inheritance, but there's really nothing
wrong with it unless you're the one who has to design a language
around it. Personally, I use MI extensively in my class hierarchies,
fully aware of what I'm getting myself into. If you don't like MI,
don't use it. But don't tell me I can't use it.


Java's answer to MI is interfaces. Interfaces are not multiple
inheritance, it's really just a very strict virtual class. They
address the first reason for inheritance, common interface, but
completely miss the second, code reuse. Interfaces force you to
reimplement the interface, for every class! What a bunch of busy
work!


Aggregation and delegation are other work arounds, but they both
involve writing wrapper methods. A situation further exasperated by
Java's lack of dynamic method generation.


And, let's not forget, multiple inheritance still allows single
inheritance if that's the way you like to do things.



Interpolation is difficult


Ok, Perl uses lots of funny characters. $this, @that, %other_things.
People like to knock this bit of line noise. One thing it does make
very easy, however, is variable interpolation:



print "I like $food, but only on $day.";

This is probably one of the most common constructs in Perl, and is
possible because of the funny characters in front of variables


Pulling off something similar in Java is not nearly as simple:



StringBuffer buf = new StringBuffer();
buf.append("I like ").append(food).append(", but only on ");
buf.append(day);

Ick. Do I really have to go through all that work just to print a few
variables in a string?


There are a few implementations of printf() in Java [11], but
they're almost as bad:



Format.printf("I like %s, but only on %s.",
new Parameters(food).add(day));

There, wasn't that easy? ;) [12]



No here-docs


Sometimes you need to have big blocks of text in your code. This
comes up very often with HTML, XML and SQL:



$sql = <<'SQL';
INSERT
INTO Stuff
(This, That, Other_Thing)
VALUES (?, ?, ? )
SQL

It's clear, it's formatted, it's unencumbered by quotes, appending
characters, etc. Means I can just paste text into my program.
Contrast this with how it's done in Java: [13]



"INSERT\n" +
"INTO Stuff\n" +
" (This, That, Other_Thing)\n" +
"VALUES (?, ?, ? )\n";

I think that speaks for itself. Wow. [14]



Bureaucratic privacy rules


I started programming by learning C++. I got up to the part about
public, private, protected, friend, etc... got very annoyed by the
unnecessary bureaucracy of it all and dropped the language, switched
to Perl. If I can't trust the programmers around me not to muck
around in my guts without good reason, I can't trust them at all. And
if they're willing to perform that bad practice, they'll probably do
more anyway. It's not worth worrying about.


This is not to say there aren't times I'd like to enforce privacy,
just don't make me have to do it all the time. [15] To paraphrase Doug
Gwyn on Unix, Perl was not designed to stop you from doing stupid
things, because that would also stop you from doing clever things.



Mandatory strong types


Right up there with the privacy rules comes the compulsion to enforce
strict type checking. Don't get me wrong, types are nice if you're
into that sort of thing, but most times I find it just another set of
unnecessary hoops to jump through. Sometimes types are appropriate,
sometimes they're not. Let me choose.


David Nicol, in a recent perl6-language@perl.org thread, put it
nicely, ``The draw of the PMAW [Perl's Magical Autoconverting
Wondervariable] is why we're all here''. We sling data all over the
place in Perl programs without hardly worrying, it's wonderful! Many
people cringe at this sort of free-wheeling approach to data
integrity, but in my experience it's not a problem.


People complain about the dizzying variety of interfaces to Perl
modules and functions, but we are saved from one thing: type casting.
You don't have to worry about what special String subclass it
requires, or that instead of taking a normal list it requires you use
a specially crafted ParameterList object. No matter how weird the
interface, it ultimately boils down to scalars, arrays and hashes. [16]


If you like types, use them. I'll even admit to wanting a strong
typing system in Perl. But don't make me use them for everything.



Conclusion


Perl is a concise language, designed to make it quick and easy to turn
thought into code. Java is a syntactically simple and consistent
language, designed to encourage good style [17] and be easy to embed.
Each has their strengths and weaknesses, but people rarely agree on
which is which. People are funny that way. Some want to save you
from yourself by restricting you. Some want to let you be yourself by
removing as many restrictions as possible. Both are fraught with
peril. I happen to like the latter peril better.


Bjarne Stroustrup has this to say:



"The connection between the language in which we think/program and the
problems and solutions we can imagine is very close. For this reason
restricting language features with the intent of eliminating
programmer errors is at best dangerous."

But I think Larry Wall sums it up best: [18]



"The very fact that it's possible to write messy programs in Perl is
also what makes it possible to write programs that are cleaner in Perl
than they could ever be in a language that attempts to enforce
cleanliness. The potential for greater good goes right along with the
potential for greater evil."



[1] I've found the first reaction most people have to this article is
immediately defending Java's design. While it's interesting to know
why, it doesn't make it any easier to write code.


[2] Since originally writing this I've bounced back to New York.


[3] Along the same path, JWZ has written a
rant about Java picking apart annoying details that
could only come from someone intimately familiar with the language.


[4] That's no-cost, open source, and unencumbered. Not this Community
License "we'll grant you the privilege to peak at our code" nonsense.


[5] Java sort of gets around this by distributing heaps more classes in
its JDK than Perl does (maybe not for long at the rate Jarko is
going), but you can only push this so far. As Adam Turoff recently
lamented on advocacy@perl.org, the Java2 SDK tarball is pushing 20
megs making Perl 5.7.1 look positively anemic at 6.7.


[6] Class::Accessor and Class::Data::Inheritable to name just two.
Damian Conway goes into gut-blowing contortions about closures and OO
in his book "Object-Oriented Perl".


[7] From the user's perspective, anyway. But that's what encapsulation
is all about, perspective.


[8] I've had more than a few "code building IDEs" suggested to solve
this, effectively glorified editor macros. One,
StructureBuilder, costs a mere
$1000 and works only on Windows.


[9] Trust me, I know. The perl source code is mostly macros.


[10] There are rumors of a Java library in the works which gives you
access to the compiler, but has all the problems of calling javac.


[11] Henrik Bengtsson's is the one I'm looking at: http://www.braju.com/.
But printf() at its best isn't nearly as elegant as variable
interpolation.


[12] Interestingly enough, Java's inability to handle variable numbers
of arguments makes the obvious Format.printf("%s %s", foo, bar)
syntax impossible.


[13] Two individuals showed me examples of how to do multi-line strings
in Java. Both forgot the newlines. Perhaps anecdotal evidence that
this sort of unnecessary complexity leads to bugs?


[14] In all fairness, you can use preprocessors to get a here-doc-ish
behavior. One such widget is
MLS.
But preprocessors, like filters in Perl, have their own set of
problems.


[15] Contrary to popular belief, you can enforce privacy in Perl.
Closures are a simply way to get private methods and several modules
provide privacy, Class::Contract in particular is air-tight!


[16] Yes, I'm oversimplifying.


[17] I'm being a gracious host here. ;)



What do you think? How would you compare Java and Perl's different language designs?


9 Comments

dday
2001-07-16 11:21:02
Wrong on Java source
The source code of the entire JDK is available for your inspection.
dday
2001-07-16 11:31:42
Printing Java variables is easy
You write:


print "I like $food, but only on $day.";


Pulling off something similar in Java is not nearly as simple:


StringBuffer buf = new StringBuffer();
buf.append("I like ").append(food).append(", but only on ");
buf.append(day);



which doesn't actuall print the variables and is overly complex anyway:


System.out.println("I like " + food + ", but only n " + day);


That wasn't so hard :-)


markfox
2001-07-16 16:35:10
Read-only source
Yes, for your inspection. The restrictive licensing on that source means it couldn't be used in the given situation.
markfox
2001-07-16 16:42:29
+ notation in a loop
Yeah, but you have to understand that the compiler reads that the same way. As far as it's concerned, that's:


System.out.println( (new StringBuffer("I like ")).append (food).append (", but only on").append (day).toString() );


One might argue that's not such a big deal, but use + notation in a loop and you'll see what a deal it is.


Having to understand that String concatenation with + uses a StringBuffer object and when that matters plays into the "'Hello World' should be one statement" point.

dday
2001-07-17 07:36:56
Read-only source
The claim made in the weblog was that there is no source available. That is wrong.
dday
2001-07-17 07:44:41
+ notation in a loop
He made an argument on usability grounds, not on performance. The relative performance of the two languages on this test is unknown.


In general, my problems with the entire weblog are:


1) The author doesn't seem to know much about Java
2) Most of his arguments are about "programming in the small." I really don't care if Hello, World is one line or 12 lines--I don't write Hello, World size programs for a living. I write large, multi-developer programs, a task for which Java is eminently more suited, IMO.


I do write a quick Perl script when I want to do a one-time text processing task, though.

anonymous2
2002-09-23 07:17:07
What about Eiffel?
I'm curious, have you everworked with Eiffel, which does have a similar "bondage and discipline" approach, but also addresses at least a few of your complaints about Java?


Those being multiple inheritance and source code availability for *everything*.

Pissed OOff
2007-06-12 02:14:52
I've not written any Perl and I've not written any Java. But you bet your OOPisms that I love your article.


If I could use a Government metaphor... Dictatorships make most everyone behave but for all the wrong reasons... they'll be killed by their oppressors if they don't.


Democracies don't guarantee that everyone will behave or that you won't be killed. You have to use good judgment, make good decisions and you'll do just fine. You could be killed but most likely only if you DON'T use good judgment and make good decisions.


Give me some freedom to make some mistakes and learn from them rather than putting me in a 10x10 box to insure my good behavior.


I rant because of Adobe's move from AS2 to AS3. I was doing just fine with AS2. I built an enterprise app that combined 7 legacy data systems, works online and offline and replicates up and down with a central server when connected. No problems.


But now if I want to move to Flex, I have to be thrown into that 10x10 cell and told, "Don't color outside the lines". Sure I can still develop with AS2 but as the crowd moves to AS3 support will diminish.


Formerly, I could simply create an array:
my_array = ["one", "two", "three"];


But now I've got to jump through all this strict typing crap:
import mx.collections.ArrayCollection;
public var my_array:ArrayCollection;
my_array.addItem("one":String);
my_array.addItem("two":String);
my_array.addItem("three":String);

What a pain in the ass!!


Like I didn't know 'my_array' was an Array!!
Like I didn't know "one" was string!!
Like I couldn't add my own data without an 'addItem' method!!


I keep reading every OOP book I can get my hands on hoping it will all crystallize one day (and maybe it will, but who will I become in the process). The big BENEFIT they all push is "code reuse".


I haven't had any problems re-using code. I open up my source code, I copy, I paste! I'm sure many OOP'ers cringe at this. What's the difference from copying the file from one project dir to another?


And if the truth be told, most code has to be modified to use with your new app anyways... that is if you're implementing the latest and greatest. Of course there's validating code, currency formatting code, etc that gets reused on a regular basis.


All in all, I'm not seeing where all this OOP strictness gains me anything. I'm not ready to drink the 'Kool-Aid' on this one.


Maybe there are others out there that could make some arguments to convince me otherwise. But I haven't seen any compelling arguments in the 5 OOP books I've read. It's like scene from the Night of the Living Dead - arms outstretched chanting, "...must OOP... this is the way its done because... well... this is the way its done."


Don't confuse my harsh words with a closed mind. It's still open, but I'm just waiting for a compelling argument.


Pissed OOff

Nimish Parmar
2008-07-28 16:22:13
Amen!


http://nimishparmar.wordpress.com/2007/01/30/perl-advocacy/