FreeMarker Blog

The official weblog of the FreeMarker project

Monday, February 20, 2006

Getting back in the Groove

Over the last couple of years, I have been doing fairly little in software development. My main activity has been online poker. I see little reason to keep this much of a secret.

Nonetheless the itch to do some coding has resurfaced (maybe it's in the blood, like a virus or something) and I decided to get back in the groove, as it were. Aside from getting more involved in FreeMarker again, I began writing some poker-related code. The current (still very green) state of things is on sourceforge.

Ruby

I originally decided to use the pokersim project as a basis to explore Ruby. So I started the pokersim code in Ruby and made very fast progress despite the huge holes in my knowledge of the language.

At some point, however, I decided, on a whim, to port the code over to Java, to compare performance as well as certain code metrics. I'll cut to the chase quickly and say that the same code (algorithmically the same code, it's different code obviously) ran 10x faster in Java. To be fair, this is because of the advanced JIT technology in Java. If you run with the JIT compiler disabled, the interpreted Java bytecode runs approximately at the same speed as the Ruby code. I am not enough of a compiler wonk to know whether the Ruby bytecode is as optimizable in theory as the Java bytecode, or in other words, whether the kind of tricks that Hotspot and its brethren do could be replicated in the Ruby world. (Perhaps not, due to Ruby's much more dynamic nature, but I don't know for sure either.)

In any case, I am really a practitioner in this field, not a theoretician, and I have to work with the tools available rather than theorize about what tools are possible. I wanted to write software that could generate a lot (like maybe some tens of thousands) of random poker deals and generate statistics. While, to be honest, I'm still not sure about the exact application, it is clear that, while 2x or 3x difference might not be so dramatic, a 10-fold speed difference could make huge differences in the usability of any software that comes out of this.

I decided to switch the project over to Java. If I take another run at Ruby, it will be when I have defined some project where I know performance is not critical. (Or it could be that, at some future point in time, Ruby performance will be much better.)

Java 1.5 and Generics

So now, rather than using pokersim as a testbed for learning Ruby, I decided to use it to explore new features in Java 1.5, in particular type-safe enums, generics, and so on.

The type-safe enum introduced in java 1.5 is unreservedly wonderful. In 1999 or 2000 I remember writing a type-safe enum class that worked in a very similar way to the way java 1.5 enums work. However, it was not part of the language, so it was much much more awkward to use.

I also started using the genericized containers in java.util.*. The main advantage of generics is notational convenience. The type-safety issue is mostly an ersatz problem. The reason is that you very rarely in my experience have a heterogeneous container anyway. For example, if the cards object below is a regular untyped ArrayList from pre-1.5 java, you might write something like:

for (Iterator it = cards.iterator(); it.hasNext();) {
Card card = (Card) it.next();
...
}

The argument that the (Card) typecast is somehow unsafe is, to my mind, merely a theoretical argument. As a practical matter, the real problem with ungenericized code like that above is its extreme verbosity. In pokersim code, I have a Cards class which is basically a ArrayList with a bunch of convenience routines.

public class Cards extends ArrayList<Card> {
...
}

and now I can write instead:

for (Card card : cards) {
...
}

And of course, the card variable is already defined within the loop. The whole thing is much more pleasant. It is shorter to type, it is easier to read and see the intent. Since such loops occur all over the place in the code, it makes a huge difference to code readability. It is already not too much worse than python code such as:

for card in cards :
....

The above is, I guess, notational nirvana. Is there any cleaner more economical way to express the idea that you are iterating over the elements in a container? The java code still has significant visual clutter, the ( and ) and { and }, delimiters that python does without. Python (and Ruby) are still much nicer languages to write (and read) code in. The generics in java 1.5 simply reduce the gap somewhat.

But again, the practical advantage of the generics here is, in my view, entirely on a notational level. The type-safety argument that is often harped on when generics are discussed strikes me as mostly an ersatz issue. Code throwing ClassCastException when you cast taking them out of containers was never that much of a problem in pre-1.5 java code.

Eclipse

Another thing in that I have started using the Eclipse IDE for my java coding. Even aside from the tool's intrinsic merits, simply the fact that my main FreeMarker collaborators (Attila, Daniel, Stephan) use Eclipse is a major consideration, and I had taken various runs at using it before. However, until now, I had never been able to keep using it. I always ended up switching back to using jEdit (along with certain key plugins like XRefactory and AntFarm) as well as a whole hodgepodge of little scripts I used from the command-line, using a lot of grep and find and so on. I actually recognized that this was a more retrograde approach, but I still abandoned Eclipse each time.

But now I am using Eclipse and there is little likelihood that I am going back.

Perhaps the main reason that I have moved to Eclipse this time for good (as compared to previous runs) is that I am running better hardware. I bought a new Dell Inspiron 9300 last September. My previous memories of using Eclipse were that it was just so monolithic and slow. Also, I am simply running the Windows XP that came with the Dell and in previous runs, I was running Eclipse on Linux, where Java is much less performant. In particular, memory usage was just frightening on linux.

Eclipse itself may have got better as well, as well as the underlying JVM. But for whatever reasons, it was mainly that the thing was such a hog that, while recognizing the tool's virtues, I couldn't use it; it just drove me nuts.

But that was then and this is now. Consider me an Eclipse convert. Eclipse is also a good argument for Java over Ruby or Python, say. I do not believe the latter have development environments that are comparable.

4 Comments:

At Tue Feb 21, 07:34:00 AM GMT+1, Blogger Attila Szegedi said...

for (Card card : cards) {
...
}

is nice - Java should catch up with latest C# developments really and allow type inference, and then you could write it even terser:

for (card : cards) {
...
}

The compiler can infer that if "cards" is List<Card>, then "card" is Card.

As for Ruby JIT-ting - it can't be made as efficient, since the language is not strongly typed. A particular implementation could use some sort of token descriptors like Objective-C does to somewhat speed up invocation of methods (descriptors could be unique mappings of names to integers for a particular invocation of the program and hence faster to lookup than method names), but you still need to do a lookup by method name on each call.

Eclipse performance indeed improved over time, although I originally used Eclipse 2.0 with a 1.3 JRE on a machine with 700MHz Pentium-III with 192 MB RAM, so everything seems faster after that :-).

However, even with latest Eclipse, it is noticeably faster and eats less RAM when run on a 1.5 JRE as compared to a 1.4 JRE, so I recommend you run it on a 1.5

 
At Tue Feb 21, 06:30:00 PM GMT+1, Blogger Jonathan Revusky said...

In general, I see ample potential for introducing nice syntactic sugar in java 1.5 and it is kind of surprising that so much low-hanging fruit was left unpicked.

For example, one surprising thing (at least for me) is that type-safe enums do not overload the comparison operators. In:


public enum EducationLevel {
PRIMARY,
SECONDARY,
UNIVERSITY,
POSTGRAD
}

The EducationLevel enum is automatically Comparable<EducationLevel> yet rather than being able to write:

if (user.educationLevel >= UNIVERSITY)

you would have to write:

if (user.educationLevel.compareTo(UNIVERSITY) >=0)

The other thing about this is that if you used the old pattern of using static final int to represent something like that, you could use the terser form that uses the regular comparison operators. So in this aspect of notational convenience, the enums are actually a step backward. (Though they have a host of other advantages, of course.)

Another similarly odd thing is that you still have to write:

list.get(i)

rather than list[i]

Why on earth not overload the meaning of [] for java.util.List? Then you would have a uniform access principle working between arrays and lists.

I have, at times thought that working with java code is somewhat reminiscent of attempts to read classic Russian literature in which all the characters have names like Ivan Ivanovich or Dimitry Dimitriyevich. It has the potential to drive one a bit batty. Consider something like the following:

Client client = (Client) clients.get(i);

In Java 1.5, using genericized containers, you can avoid the typecast in the line above, but it does not go as far as it should. It still maintains a distinctly Doystoyevsky/Tolstoy sort of flavor. As far as I can see, there is little real obstacle (other than conservatism) to allowing people to write simply

client = clients[i];

as you would in python, say. That you don't specify that the loop variable client is of type Client since it can be deduced from the type of the clients container and that clients[i] could be taken as a shorthand for clients.get(i) when clients is a List object....

And actually, clients[i] is short enough that you might not even bother to define an intermediate client variable. The main reason for defining the client variable in the java code is that otherwise you have to write obviously barbaric things like:

Account account = ((Client) clients.get(i)).getAccount();

so instead you write on 2 lines:

Client client = (Client) clients.get(i);

and then:

Account account = client.getAccount();

But in a more perfect world, surely you'd write:

account=clients[i].account;

and avoid oodles of typing. It reallyl is quite severe when you look at it and is an example of the fact that one can get used to anything. I have to admit that writing the kind of code examples above in pre-generics Java did just seem kind of normal to me... Stepping back from this a bit, it should be considered unacceptable IMO.

Getting back a bit to FreeMarker as a topic, it is clear in the above discussion that I think that notational convenience can be quite an important factor in productivity.

I may have given the impression that I think otherwise in FM vs. Vel discussions that often center on syntax. But the thing is that there seems to be an attempt (conscious or not, probably not conscious) on the part of the Velocity camp to foment some kind of urban legend about Velocity's syntax being so much nicer than FreeMarker's.

Any comparison of the main constructs shows that there is generally little or no difference. Moreover, sometimes, a comparison of how much typing is necessary to express something favors FreeMarker -- though only slightly. For example:

<#if name = "Joe">

is actually one character shorter than:

#if ($name == "Joe")

But, on the whole, the idea that non-technical page designers would have such an easier time mastering the VTL above rather than the FTL strikes me as baseless speculation of the worst sort.

I guess the basis of the urban legend about FreeMarker syntax is the idea that FreeMarker syntax is XML-based.

And XML-based languages are outrageously verbose. After all, just writing:

<PROPERTY key="foo" VALUE="bar"/>

is outrageously verbose compared to just writing

foo=bar

in a .properties file. But other stuff like:

<fm:if test="name='Joe'">

is very verbose and has real readability issues.

But the fact is that this is all based on a misunderstanding: FreeMarker syntax is not XML-based. It is XML-ish.

Regarding Eclipse, it's amazing that you managed to use it on a 700 Mhz machine with 192 megs of RAM. My own experience lead me to think that (at least by my standards) it would not be remotely usable on such hardware.

 
At Tue Feb 21, 06:55:00 PM GMT+1, Blogger Attila Szegedi said...

As for typesafe enums comparison operator and similar unpleasant questions asked from Josh Bloch by Ted Neward, watch

http://www.javapolis.com/confluence/display/JP05/Joshua+Bloch+and+Neal+Gafter+interview

if you have time.

Your "Russian notation" remark rocks :-)

As for Eclipse on anemic hardware - yes, it was pain at times, when things ground to a halt I'd restart it etc. but in the end I stuck with it as I really wanted an integrated IDE and it was still much less of a resource hog than NetBeans (and had tons of other advantages over it)

 
At Sat Feb 25, 11:29:00 PM GMT+1, Blogger Dániel Dékány said...

Regarding generics... I think it's more than something that saves you from typing castings and like. Think about API-s. You see that the parameter is a list of what, without reading the JavaDoc. Or think about private fields, which usually don't have JavaDoc. Even before I have heard about 1.5 generics, I very often written things like List/*<MyClass>*/, just to make the code more readable.

 

Post a Comment

<< Home