Wednesday, December 23, 2009

"That" Java example and preaching to the converted

There is one example of Java code that keeps coming up. I have seen variants of it at conference presentations several times, in Venkat Subramaniam's Programming Groovy and most recently in an essay by Neal Ford in The ThoughtWorks Anthology. This example compares Java with a scripting language, and goes usually something like this (here I combine all the worst practices from the books in one example):

JAVA VERSION:

import java.io.*;

public class ReadFile
{

public ReadFile(String path)
{
BufferedReader reader = null;
try
{
reader = new BufferedReader(
new FileReader(path));
String line = null;
while((line = reader.readLine()) != null)
{
System.out.println(line);
}
}
catch(FileNotFoundException ex)
{
ex.printStackTrace();
}
catch(IOException ex)
{
ex.printStackTrace();
}
finally
{
try
{
if (reader!=null)
{
reader.close();
}
}
catch (IOException ex)
{
//Ignore
}
}
}

public static void main(String[] args)
{
new ReadFile("thoreau.txt");
}
}


GROOVY VERSION:

println new File('thoreau.txt').text


Wow, 1 line instead of almost 50! Java must really suck! The problem with this is that the Groovy version is obviously just a one-off, there is no attempt to make a reusable module or do robust error handling. If there is an error, the program just terminates with en error message. We can do exactly the same with the Java version and cut down the number of lines significantly if we just throw the exception. We can reduce the number of lines even more if we use a "modern" (1.5) API and the Java coding conventions for where to place brackets, etc:


import java.io.File;
import java.util.Scanner;

public class ReadFile {

public static void main(String[] args) throws Exception {
File in = new File("thoreu.txt");
String contents = new Scanner(in).useDelimiter("\\Z").next();
System.out.println(contents);
}

}


It can be made a one or two lines shorter still, (at the price of a dependency on a big jar) if you are are willing to use an external library such as Apache Commons IO. Or I could have squeezed the three lines of logic into one, but I think this is a reasonable trade off between readability and verbosity. But this new and improved example is still much longer than the Ruby/Groovy/Scala/etc versions (especially if you count characters instead of lines); and arguably less clear (What's a scanner? What does "\\z" mean?).

The problem with using the original Java example is that will mainly convince those who are firmly in the "Yeah, Java totally sucks" camp. Even a very junior Java developer, who is curious about learning about a new language will see that the original example is either
a) Written by a rank amateur (unlikely considering the caliber of the authors) Or -
b) Wildly exaggerated to make Java look as bad as possible.
And that will make them less receptive to the text as a whole. With the number of active Java programmers probably (still) in the hundreds of thousands, alternative languages have a large number of possible recruits and allies. I would prefer to see a better example to convince them that it is worthwhile to look at other languages.

Monday, August 10, 2009

Pragmatic argumentation

I read Chad Fowler's The Passionate Programmer this weekend. All in all a pretty good book which I recommend. Remaining from the previous edition however is one of my least favorite paragraphs in the book.


In his essay "Great Hackers", Paul Graham annoyed the industry with the assertion that Java programmers aren't as smart as Python programmers. He made a lot of stupid Java programmers mad (did I say that?), causing a lot of them to write counterarguments on their websites. The violent reaction indicates that he touched a nerve.


So if, purely for the sake of argument mind, I claimed that "Chad Fowler is a racist" (he's not) and he got really upset about it, his reaction is an indication that I am on to something? No, only if you are on the level of a tabloid journalist. If you come with a hurtful accusation and people get really upset, that is an indication you are being a dick.

Sunday, May 3, 2009

Notes on dataflow concurrency

At a conference, I heard someone say something to the effect of: "Declarative dataflow concurrency is awesome. You can't get deadlocks! It all just works, and it is so beautiful".

If you are unfamiliar with dataflow concurrency, it is a technique used in some languages, where a program, if it reaches a statement that requires the use of a variable which hasn't been assigned a value yet, pauses until the variable has been assigned by another thread and then continues the computation as if nothing had happened.

It is pretty neat, but I thought to myself - "Hang on, if we have two threads that each wait for the other to assign a variable, won't we get a circular dependency between them? Or if there is just one executing thread, won't that block forever? I don't understand, that doesn't sound like much different from what I'm used to...?"

Now a month later, I am currently reading the book "Concepts, Techniques and Models of Computer Programming" by Ray and Haridi. And indeed, on page 48 they state:

The computation models of this book use [dataflow programming]. This is unreasonable in a sequential system, since the program will wait forever. It is reasonable in a concurrent system, where it could be part of normal operation that some other thread binds the varialbe. [Dataflow programming] introduces a new kind of program error, namely a suspension that waits forever. For example, if a variable name is misspelled then it will never be bound. A good debugger should detect when this occurs.

So even if they wait on an infinitely unbound variable instead of lock that is never released, the experience for the user would appear to be much the same - a program that "hangs" without producing the desired result. I wrote this little snipped in Mozart to demonstrate:

declare

Y

X

thread X=Y+1 end

Y=X+1 end

{Browse X}


And indeed the browse window never appears. The main thread blocks on line 5, the spawned thread on line 4, each waiting for an unbound variable.

But even though it hasn't been stated outright in the book (at least not yet, I'm at page 350), I think there is an important difference compared to threaded programs as they are usually written in, for instance, Java. The Mozart program is deterministic (if written in a completely declarative style). It will *always* block, no matter how the threads are scheduled, which makes this programming error easier to detect and (hopefully) to locate and fix.

So what the person at the conference perhaps meant, was that the programs written in dataflow concurrency style don't have *race conditions*.

Friday, January 30, 2009

Adept updater crash

I had been hoping to blog more about programming stuff, but here has been lots of "yak shaving" activities for me lately. Linux is still a hairy beast, even if things are slowly getting better. And here is another one!

The "Adept updater tool" in KDE, which has a little icon in the systray informing you when important updates are unavailable, is light-years better than the default behavior of the Windows Update tool in Vista -

("I have downloaded updates and will restart now, shutting down your programs". "I am configuring updates, you may not turn off your computer right now.", "Now I'm going to restart your computer again". "This is a blue screen of death" "Could not start Windows. Would you like to try to restore your computer to last known working configuration?" No joke, this happens to me with SP1 for Vista, can't install it on my Dell laptop)

- but Adept is not completely bug- or annoyance-free either. Yesterday when downloading a new Linux kernel to my Kubuntu system, my update progress stopped suddenly. A command line style menu window had popped up asking if I wanted to keep my old locally changed grub conf file, or replace it with a new one. While Adept could show the menu to me if I went to the "details" tab, it could not process any input from me and transmit it to the install script, so I had to kill the Adept process.

Next time I tried to restart Adept, it said the update database was locked because another program was using it. This is the solution to this problem (most of it curtesy of "harleqinguy" at Linuxquestions.org)

sudo rm /var/lib/dpkg/lock
Removes lock file - only do if you are sure all programs which may access the update db are terminated, but the lock still remains.

sudo dpkg --configure -a
Reconfigures downloaded but not yet installed update packages, and backs up configuration files. Mainly to test if you can run update tools, and to try to fix any configuration mistakes you may have done

Now you can restart Adept, but trying to update your system through it will only lead to the same issues again, to get by this problem and get your shiny new kernel installed, go to your trusty command line and run

sudo apt-get upgrade

Thursday, January 29, 2009

KDE login jingle

To turn off the annoying KDE login/logout jingles (which doesn't respect your sound settings and plays loudly when you are at the library, at a lecture, a conference, next to someone asleep, etc, unless you remembered to have headphones plugged in):

Go to the KDE system settings program, click "Notifications" icon, "System notifications", "Applications" tab, select "KDE Systems notification" in dropdown menu, then select "login", then uncheck the "Play a sound" checkbox.

Done. Whew. They hid that pretty well.

Sunday, January 25, 2009

Wine eject cd/dvd problem solved

A problem that has popped up for me several times and whose solution can be hard to find when Googling -

If you are trying to install a Windows game or application on Linux with Wine, always start the command from "outside" the cd.
I.e. - always DO write wine /media/cdrom/setup.exe
Do NOT write

cd /media/cdrom
wine setup.exe

If you are promted to insert the next disc, but Linux won't let you do the unmount command because "device or resource is busy" - try
wine eject d:

If all else fails, copy the whole disc to hard drive and run from there.