POV-Ray : Newsgroups : povray.off-topic : Java is verbose : Java is verbose Server Time
29 Jul 2024 04:26:51 EDT (-0400)
  Java is verbose  
From: Invisible
Date: 10 Apr 2012 08:10:50
Message: <4f84234a$1@news.povray.org>
I realise this is a radical and controversial thing to say, but it is. :-P

Suppose, for example, that I wanted to implement a lambda expression 
interpreter. For those who don't know, a lambda expression has one of 
three possible forms:

   1. A variable name.
   2. A lambda function. This consists of a lambda, followed by a 
variable name, followed by an arrow, followed by any valid lambda 
expression.
   3. A function application. This consists of any two valid lambda 
functions, separated by an empty space.

Usually brackets are used to disambiguate when such expressions are 
written as text. But conceptually, the above exactly describes the form 
of a lambda expression.

Now, suppose we want to define a data structure for storing such 
expressions, and a way to convert one into text. (Converting /from/ text 
is obviously much harder.)

In Haskell:

   data Expression =
       Variable String                |
       Lambda   String     Expression |
       Apply    Expression Expression
     deriving Show

This defines our data structure. The final line tells the compiler to 
auto-generate the code for conversion to text. However, if you don't 
like the way the compiler's auto-generated code does it (and we don't, 
in this case), it's not hard to write it yourself:

   lambda_text :: Expression -> String
   lambda_text e =
     case e of
       Variable n   -> n
       Lambda   n e -> "λ " ++ n ++ " → " + lambda_text e
       Apply    e f -> lambda_text e ++ " " ++ lambda_text f

In reality, you /probably/ want to make it insert some brackets and 
stuff, but the above is the gist of it. If we remove the "deriving" 
line, we have a total of 10 lines of code here.

Now let's try the same thing in Java:

   public abstract class Expression {}

   public class Variable extends Expression
   {
     private String Name;

     public Variable(String n) {this.Name = n;}

     public String toString() {return this.Name;}
   }

   public class Lambda extends Expression
   {
     private String     Variable;
     private Expression Body;

     public Lambda(String v, Expression b)
     {
       this.Variable = v;
       this.Body     = b;
     }

     public String toString()
     {
       return "λ " + this.Variable.toString() + " → " + 
this.Body.toString();
     }
   }

   public class Apply extends Expression
   {
     private Expression LHS, RHS;

     public Apply(Expression l, Expression r)
     {
       this.LHS = l;
       this.RHS = r;
     }

     public String toString()
     {
       return this.LHS.toString() + " " + this.RHS.toString();
     }
   }

If your screen is anything like mine, that lot doesn't even fit on one 
page. This is /a lot/ of code. And yet it doesn't even "do" anything, as 
such. It just lets you construct data structures, and print them out. 
The same thing as the 10 lines of Haskell code did. I count 44 lines. 
Or, if you're feeling generous, 36 non-blank lines. And I even tried to 
scrunch Lambda.toString() onto one line, even though it's really too big.

Now suppose that, for some strange reason, I want to be able to check 
whether two expressions are the same. (Realistically, I can't think why 
you'd want to do that for anything except variables.) In Haskell, I can 
simply append "deriving Eq", and the compiler will write the code for me 
in the obvious way. In this instance, it does the right thing. In 
Java... well OK, I'll go easy on Java and only write the code for 
Variable. Here goes:

   public class Variable extends Expression
   {
     private String Name;

     public Variable(String n) {this.Name = n;}

     public String toString() {return this.Name;}

     public boolean equals(Object obj)
     {
       if (obj == null) return false;

       if (obj instanceof Variable)
       {
         Variable v = (Variable) obj;
         return this.Name.equals(v.Name);
       }

       return false;
     }

     public int hashCode() {return this.Name.hashCode() + 9;}
   }

OK, so only 14 lines of actually new code. The hashCode() override is 
not /strictly/ necessary, but the IDE whines like hell if you don't, and 
it's highly likely that you're going to put variables as keys into a 
HashMap at some point, in which case hashCode() had better work correctly!

In Haskell, you can simply say

   e `equals` f =
    case (e, f) of
      (Variable x, Variable y) -> x == y

and you're done.

In Java, you have to check whether the argument is null. (Impossible in 
Haskell.) You have to check whether the argument is of a comparable 
class. (Haskell's static type checking does that for you at 
compile-time. Actually Java's generics could do that too if they 
extended it a teeny weeny bit... but they haven't.) Then you have to 
actually type-cast it. (Unnecessary in Haskell due to static checking.) 
Then, and only then, can you do the actual test. But because it's Java 
and it sucks, you can't just say this.Name == v.Name; that would do a 
pointer comparison, not a string comparison. So you must instead do 
this.Name.equals(v.name), which is obviously far more readable. :-P

On the plus side, the IDE will generate some of this code for you. On 
the minus side, you still have to /read/ it. And perhaps the worst thing 
about the above Java code isn't that it's 44 lines, but that it's in 4 
separate files, when /obviously/ it's notionally a single entity. (Then 
again, I think if you make the classes private - excuse me, "package 
scope" - then they may all be put in one file.)

In consequence to the above, I just spent an entire morning coding in 
Java, and all I actually have to show for it is a boat-load of classes 
which can hold data and generate a graphical representation of 
themselves. They have no actual /behaviour/ yet. It's taken me this long 
just to do that... Man, Java is a blunt knife! (But oh so hard to hurt 
yourself with... yeah, right!)


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.