Tony Bowden pointed out a JWZ rant simply entitled 'java sucks'.  He
makes a number of specific, solid technical points about Java which I
think have relevance to Perl.

http://www.jwz.org/doc/java.html

What follows are some of the more interesting excerpts.  **These are
my comments***

Here's the quick list of things both Java and Perl are missing/doing wrong:

        - Inline methods/macros/preprocessor/flet
        - Poor iteration over characters in a string
        - Everything should be an object to aid abstraction
        - Integers should automagically degrade to bignums.
        - Accessor methods should degrade to direct slot (hash) access
        - Discovery of file system limitations are missing
        - Too much application-level crap in the standard library.


And in his own words...
Here's things that Java and Perl are missing:

   o It's far from obvious how one hints that a method should be inlined, or
     otherwise go real fast. Does `final' do it? Does `private final' do it? 
     Given that there is no preprocessor to let you do per-function shorthand,
     and no equivalent of Common Lisp's flet (or even macrolet), one ends up
     either duplicating code, or allowing the code to be inefficient. Those
     are both bad choices.

        **constant.pm is anemic and Filter::cpp relies on an existing C
          preprocessor (ie. won't work on most Windows and Mac)**


   o I can't seem to manage to iterate the characters in a String without
     implicitly involving half a dozen method calls per character.

        **while its not quite that bad in Perl, its still harder than in
          C (ie. the "string is just an array of characters" approach).
          However, regexes make this technique rare.**

   o This ``integers aren't objects'' nonsense really pisses me off. Why did
     they do that? Is the answer as lame as, ``we wanted the `int' type to be
     32 bits instead of 31''? (You only really need one bit of type on the
     pointer if you don't need small conses, after all.)

     The way this bit me is, I've got code that currently takes an array of
     objects, and operates on them in various opaque ways (all it cares about
     is equality, they're just cookies.) I was thinking of changing these
     objects to be shorts instead of objects, for compactness of their
     containing objects: they'd be indexes into a shared table, instead of
     pointers to shared objects.

     To do this, I would have to rewrite that other code to know that they're
     shorts instead of objects. Because one can't assign a short to a variable
     or argument that expects an Object, and consequently, one can't invoke
     the equal method on a short.

     Wrapping them up in Short objects would kind of defeat the purpose: then
     they'd be bigger than the pointer to the original object rather than
     smaller.

        **I'm seeing more and more utility to the "everything is an object"
          approach myself.  Tying sort of addresses this, but performance
          is horrid.  However, without strong typing, it isn't as needed**

   o After all this time, people still think that integer overflow is better
     than degrading to bignums, or raising an exception?

   o As far as I can see, there's no efficient way to implement `assert' or
     `#ifdef DEBUG'. Java gets half a point for this by promising that if you
     have a static final boolean, then conditionals that use it will get
     optimized away if appropriate. This means you can do things like

         if (randomGlobalObject.DEBUG) { assert(whatever, "whatever!"); }

     but that's so gratuitously verbose that it makes my teeth hurt. (See
     also, lack of any kind of macro system.)

        **ran into this problem with Carp::Assert**

   o The locking model is broken.
          
        o First, they impose a full word of overhead on each and every object,
          just in case someone somewhere sometime wants to grab a lock on that
          object. What, you say that you know that nobody outside of your code
          will ever get a pointer to this object, and that you do your locking
          elsewhere, and you have a zillion of these objects so you'd like
          them to take up as little memory as possible? Sorry. You're screwed.

        o Any piece of code can assert a lock on an object and then never
          un-lock it, causing deadlocks. This is a gaping security hole for
          denial-of-service attacks.

   o There is no way to signal without throwing: that is, there is no way to
     signal an exceptional condition, and have some condition handler tell you
     ``go ahead and proceed anyway.'' By the time the condition handler is
     run, the excepting scope has already been exited.

   o The distinction between slots and methods is stupid. Doing foo.x should
     be defined to be equivalent to foo.x(), with lexical magic for ``foo.x =
     ...'' assignment. Compilers should be trivially able to inline
     zero-argument accessor methods to be inline object+offset loads. That way
     programmers wouldn't break every single one of their callers when they
     happen to change the internal implementation of something from something
     which happened to be a ``slot'' to something with slightly more
     complicated behavior.

   o The file manipulation primitives are inadequate; for example, there's no
     way to ask questions like ``is the file system case-insensitive?'' or,
     ``what is the maximum file name length?'', or ``is it required that file
     extensions be exactly three characters long?'' Which could be worked
     around, but for:

        **File::Spec doesn't quite cover all this**

   o The architecture-interrogation primitives are inadequate; there is no
     robust way to ask ``am I running on Windows'' or ``am I running on
     Unix.''

        **We have $^O, but it requires parsing every time**

   o What in the world is application-level crap like checkPrintJobAccess()
     doing in the base language class library? There's all kinds of
     special-case abstraction-breaking garbage like this.


Here's his gripes about Java that Perl has covered:

   o It's hard to live with none of: lexically scoped local functions; a macro
     system; and inlined functions.

   o I really hate the lack of downward-funargs; anonymous classes are a lame
     substitute. (I can live without long-lived closures, but I find lack of
     function pointers a huge pain.)

   o The fact that static methods aren't really class methods (they're
     actually global functions: you can't override them in a subclass) is
     pretty dumb.

   o Two identical byte[] arrays aren't equal and don't hash the same.

   o Generally, I'm dissatisfied with the overhead added by Unicode support in
     those cases where I'm sure that there are no non-ASCII characters. There
     ought to be two subclasses of an abstract String class, one that holds
     Unicode, and one that holds 8-bit quantities. They should offer identical
     APIs and be indistinguishable, except for the fact that if a string has
     only 8-bit characters, it takes up half as much memory!

        **umm, Perl covers this more or less**

   o Interfaces seem a huge, cheesy copout for avoiding multiple inheritance;
     they really seem like they were grafted on as an afterthought. Maybe
     there's a good reason for them being the way they are, but I don't see
     it; it looks like they were just looking for a way to multiply-inherit
     methods without allowing call-next-method and without allowing instance
     variables?

   o And in related news, it's a total pain that one can't iterate over the
     contents of an array without knowing intimate details about its contents:
     you have to know whether it's byte[], or int[], or Object[]. I mean, it
     is not rocket science to have a language that can transparently access
     both boxed and unboxed storage.

   o I sure miss multi-dispatch. (The CLOS notion of doing method lookup based
     on the types of all of the arguments, rather than just on the type of the
     implicit zero'th argument, this).

        **We mostly have this covered**

   o Relatedly, there are no ``weak pointers.'' Without weak pointers and a
     working finalization system, you can't implement a decent caching
     mechanism

        **Hey, why isn't WeakRef in the core?**

   o The notion of methods "belonging" to classes is lame. Anybody anytime
     should be allowed to defined new, non-conflicting methods on any class
     (without overriding existing methods.) This causes no
     abstraction-breakage, since code which cares couldn't, by definition, be
     calling the new, ``externally-defined'' methods.

   o It comes with hash tables, but not qsort? Thanks!

   o There is no way to access link() on Unix, which is the only reliable way
     to implement file locking.

   o There is no way to do ftruncate(), except by copying and renaming the
     whole file.

   o Is "%10s %03d" really too much to ask? Yeah, I know there are packages
     out on the net trying to reproduce every arcane nuance of printf(), but
     controlling field width and padding seems pretty darned basic to me.




-- 

Michael G. Schwern   <[EMAIL PROTECTED]>    http://www.pobox.com/~schwern/
That which stirs me, stirs everything.
        -- Squonk Opera, "Spoon"

Reply via email to