POV-Ray : Newsgroups : povray.off-topic : Java: Some things never change Server Time
29 Jul 2024 08:19:33 EDT (-0400)
  Java: Some things never change (Message 1 to 10 of 24)  
Goto Latest 10 Messages Next 10 Messages >>>
From: Invisible
Subject: Java: Some things never change
Date: 2 Apr 2012 05:07:16
Message: <4f796c44$1@news.povray.org>
Yesterday I was sitting at my PC, listening to Alisha's Attic and coding 
in Java.

So... doing what I was doing 10 years ago, then. :-P

Some things change, others remain the same. Java ditched the Abstract 
Window Toolkit and went with Swing. It's still absurdly over-complicated 
and confusing. At least it appears to be very slightly better 
documented. (Thankfully, NetBeans has a UI painter. Weirdly, it doesn't 
let you specify alignment constraints or anything more sophisticated 
then "put this button here". So if you resize the window, it's anybody's 
guess what will happen.)

Figuring out how to do a tree view was fun. Fortunately, there's a 
tutorial. Otherwise I would never have figured out that each tree node 
is an object of class DefaultMutableTreeNode. (DefaultTreeNode won't cut 
it, apparently.) I'm still waiting on why you need a JTree object 
pointing to a DefaultMutableTreeModel object which /then/ points to a 
DefaultMutableTreeNode representing the root of the actual tree being 
displayed...

Just like in the old days, there are some very odd design decisions. For 
example, you would /think/ that the tree would default to being 
expanded. Failing that, you might guess that defaulting to being 
collapsed would be reasonable. But in fact, Swing does neither. What it 
/actually/ does is that _the root node_ defaults to being expanded, 
while all other nodes default to being collapsed. Nice consistency 
there. :-P

You would think there would be a method that says "expend this tree 
node". Well, there isn't. Instead, what you have to do is create a "tree 
path" object which describes the location of the tree node you want to 
expand. Or, alternatively, you can use a row number. (Christ only knows 
how /that/ actually works!) You might expect to find an "expand all" 
method, with a matching "collapse all" method. You would be 
disappointed. Yes, if you just want to expand all the nodes in the tree, 
you have to actually manually write a for-loop to repeatedly call the 
expand() method.

Also, depending on exactly which way you modify the tree, you may or may 
not have to call reload() on the tree widget (not the tree model or the 
tree root or the tree node you just changed) to make the change visible. 
Otherwise the change only becomes visible if the window has to repaint 
for some reason. No, hiding and revealing the window does not make it 
repaint. But resizing it does.

Just like in the old days, things are still a bit buggy. For example, 
Swing has a random feature where if some display text begins with the 
token "<html>", then some but not all HTML formatting commands are 
accepted. Of course, in real HTML, you'd mark chunks of stuff with tags, 
and then use CSS to decide how to actually format that. Swing appear to 
only understand raw HTML formatting commands. Naturally, the exact set 
of commands supported is not documented anywhere.

The really buggy thing though is this: If you disable a widget, its 
label goes grey. But if the widget uses HTML formatting, the text no 
longer turns grey. Presumably because they haven't figured out how to 
combine that with the HTML formatting. (Surely the solution is just to 
apply a little alpha blending...)

There's a ticket for it on the bug tracker. But it's not marked as a 
bug, but rather as a "feature request". (Yes, that's right. The software 
working correctly in a certain special case is a "feature request", not 
a basic expectation.) The priority is set to "very low". There are 
thousands of replies, most of them containing elaborate Java source code 
to work around the problem. People - THIS IS NOT HOW TO CREATE QUALITY 
SOFTWARE! >_<

In other news, there appears to be no way to make NetBeans halt on 
exceptions. Like, if an exception is thrown, I would like to halt the 
debugger at the line where it was thrown, so I can inspect the program 
state and, you know, /debug it/. But apparently no, you cannot do that. 
Because technically, the exception is thrown, and then /caught/ by the 
top-level exception handler. And handled exceptions "don't count". Never 
mind the fact that Java's checked exceptions mentality /requires/ you to 
catch all exceptions. Your code actually won't compile (and hence won't 
run) if you don't do this. *sigh*

I have at least found out how to single-step Java code in the debugger 
now. But that doesn't work at all with GUI code. You can't single-step 
into an event handler that only runs when the user clicks a button. You 
also apparently cannot set breakpoints - I can only presume because the 
code runs in a thread other than the one the debugger was expecting. 
Seriously, nobody thought to test that one?

In about two days of coding, I did manage to write my program, and have 
it work. It's ages since I wrote a program with a real, native-looking 
GUI. I'd forgotten how satisfying that is. (When it actually works!) But 
now one of the program features has a small bug in it, which I am 
seemingly powerless to track down. Time for the next iteration of my 
prototyping...


Post a reply to this message

From: Invisible
Subject: Re: Java: Some things never change
Date: 2 Apr 2012 07:06:28
Message: <4f798834$1@news.povray.org>
On 02/04/2012 10:07 AM, Invisible wrote:
> Yesterday I was sitting at my PC, listening to Alisha's Attic and coding
> in Java.
>
> So... doing what I was doing 10 years ago, then. :-P

It's interesting, actually. I needed a parser. Since Java doesn't have 
any parsing libraries, I started writing one. But I made the mistake of 
trying to write it the way you'd write in in Haskell. Pro tip: DON'T DO 
THAT!

You see, in Haskell, it's trivial to write a function that takes some 
other function as its argument to do some key operation, or to implement 
the continuation, or whatever. But in Java, that's wicked-hard. You'd 
have to write an entire class for every "function" you want to pass as a 
parameter. (The fact that "anonymous inner classes" even exist tells you 
how badly some Java programmers want first-class functions...)

In Haskell, you'd write a parser combinator library. You have a couple 
of primitive parsers, and then you have functions that construct more 
sophisticated parsers from simpler ones. Trouble is, in Java every 
"parser" has to be an entire class. And where in Haskell you can just 
say "foo 1 2 3" and get a 1-argument function, in Java you must say

   public class Foo extends Parser
   {
     private int arg1, arg2, arg3;

     public Foo(int a1, int a2, int a3)
     {
       this.arg1 = a1;
       this.arg2 = a2;
       this.arg3 = a3;
     }
   }

This is before you even /implement/ the actual functionality of the 
thing! In short, Java makes this kind of thing excruciatingly verbose. 
Also, unlike Haskell, it's not designed to be used this way at all, and 
so it doesn't optimise all this overhead away. I ended up writing a huge 
mountain of very complex and buggy code that's a nightmare to understand.

So then I took a step back, and tried to write a parser the way a Java 
programmer might do it. And you know what? The lexer is pretty simple. 
You do something like

   public class Lexer
   {
     private String buffer;
     private int    index;

     public Lexer(String in)
     {
       this.buffer = in;
       this.index  = 0;
     }

     private char Peek() {return this.buffer.chatAt(this.Index);}

     private void Next() {this.index++;}

     private boolean EOF() {return this.Index < this.buffer.length();}

     public Token GetNextToken() {...}
   }

There's basically two types of token: Ones that consist of just one 
special character, and ones that consist of a run of characters of a 
certain type. In Haskell, you'd abstract out these patterns, but in Java 
that's too painful. The single-character case is trivial to handle, and 
there are only two types of character run to worry about, so the code 
repartition isn't too bad.

Next, you need to parse the tokens into a parse tree. Now there's 
several ways to do that. The way I tried to do it was Dijkstra's 
shunting algorithm. In it's original form, it takes a list of tokens and 
builds a Polish reversed list. But it's easy to modify it to build a 
parse tree instead.

The original algorithm looks like

   - Read token.
   - If operand, output.
   - If operator, push to the operator stack. (Possibly unstacking and 
outputting some existing operators first.)
   - At the end, unstack all remaining operators as above.

All you gotta do is keep the operands on a stack as well, and when you 
unstack an operator, you pull its operands off the operand stack, make a 
little expression tree out of it, and push that back to the operand 
stack. At the end, there should be one operand left, which is your 
expression tree.

The really tricky part is handling brackets and function calls. In fact, 
I discovered that my parser fails for functions that take zero 
arguments. It appears the only way to fix this is for the parser to 
"know" how many arguments each function is supposed to take - which is a 
dependence I really don't want to add. (The alternative is to hack 
around the problem with status flags, which is a bit messy.)

Apart from empty function calls, my parser works. Trouble is, every 
possible operator token becomes a whole class, because every token 
behaves differently. (In particular, most tokens need to be turned into 
/expressions/ at some point.) So you end up with a rather large 
profusion of classes!

I ended up with 12 concrete token classes, plus about 5 abstract classes 
to handle shared functionality. Add on one class for the parser (which 
manages the two stacks), one class for the lexer, and one class for the 
parser exception (in Java, an exception is a class) and we have a grand 
total of 20 classes to implement this simple little parser. And it 
doesn't even give decent error messages!


Post a reply to this message

From: nemesis
Subject: Re: Java: Some things never change
Date: 2 Apr 2012 19:06:33
Message: <4f7a30f9$1@news.povray.org>
Invisible escreveu:
> It's interesting, actually. I needed a parser. Since Java doesn't have 
> any parsing libraries

LOL


Post a reply to this message

From: Invisible
Subject: Re: Java: Some things never change
Date: 3 Apr 2012 04:16:53
Message: <4f7ab1f5$1@news.povray.org>
>> It's interesting, actually. I needed a parser. Since Java doesn't have
>> any parsing libraries
>
> LOL

What I obviously /meant/ was that it doesn't come with one 
out-of-the-box. Sheesh...


Post a reply to this message

From: nemesis
Subject: Re: Java: Some things never change
Date: 3 Apr 2012 09:14:04
Message: <4f7af79c$1@news.povray.org>
Em 03/04/2012 05:17, Invisible escreveu:
>>> It's interesting, actually. I needed a parser. Since Java doesn't have
>>> any parsing libraries
>>
>> LOL
>
> What I obviously /meant/ was that it doesn't come with one
> out-of-the-box. Sheesh...

well, neither is parsec.  Still, you didn't go on writing your own, did 
you? :p


Post a reply to this message

From: Invisible
Subject: Re: Java: Some things never change
Date: 3 Apr 2012 09:41:33
Message: <4f7afe0d$1@news.povray.org>
>>>> It's interesting, actually. I needed a parser. Since Java doesn't have
>>>> any parsing libraries
>>>
>>> LOL
>>
>> What I obviously /meant/ was that it doesn't come with one
>> out-of-the-box. Sheesh...
>
> well, neither is parsec. Still, you didn't go on writing your own, did
> you? :p

When you install Haskell, Parsec /is/ included in the default install. 
(Unless you go with one of the more obscure Haskell implementations.)

When you install the normal JDK bundle, it doesn't include a parsing 
library.

OTOH, when you install Haskell, you don't get any GUI capabilities, but 
with the JDK you do. They just come with different sets of libraries, 
that's all.


Post a reply to this message

From: Invisible
Subject: Re: Java: Some things never change
Date: 3 Apr 2012 11:39:59
Message: <4f7b19cf$1@news.povray.org>
On 02/04/2012 10:07 AM, Invisible wrote:

> Just like in the old days, things are still a bit buggy.

Wait - you implemented generics but didn't implement generic array 
creation??!

*facepalm*


Post a reply to this message

From: Invisible
Subject: Re: Java: Some things never change
Date: 5 Apr 2012 08:51:05
Message: <4f7d9539$1@news.povray.org>
Gotta love the way NetBeans displays stdout and stderr in different 
colours, but the two streams don't actually line up!

(For example, if the program throws an exception, the exception text 
appears a couple of lines /above/ the line of output where the exception 
was actually thrown...)


Post a reply to this message

From: Darren New
Subject: Re: Java: Some things never change
Date: 5 Apr 2012 22:12:20
Message: <4f7e5104$1@news.povray.org>
On 4/3/2012 6:41, Invisible wrote:
> When you install the normal JDK bundle, it doesn't include a parsing library.

Now, grasshopper, do you understand why every configuration file everywhere 
in any Java-based system is based on XML or property files?

-- 
Darren New, San Diego CA, USA (PST)
   "Oh no! We're out of code juice!"
   "Don't panic. There's beans and filters
    in the cabinet."


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: Java: Some things never change
Date: 6 Apr 2012 05:02:21
Message: <4f7eb11d$1@news.povray.org>
On 06/04/2012 03:12 AM, Darren New wrote:
> On 4/3/2012 6:41, Invisible wrote:
>> When you install the normal JDK bundle, it doesn't include a parsing
>> library.
>
> Now, grasshopper, do you understand why every configuration file
> everywhere in any Java-based system is based on XML or property files?

Oh, well, that's almost an /advantage/. Why invent yet another file 
format when you can use an existing well-supported one?


Post a reply to this message

Goto Latest 10 Messages Next 10 Messages >>>

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