Friday, July 06, 2007

Groovy and the Lambda Calculus

I've been playing around with the Groovy language, and have recently been involved in a discussion regarding the addition of closures to Java. Tangents lead to tangents, and all of a sudden, I find myself reading about Perl and the Lambda Calculus. Oy.

I had just started trying to get my head around the idea of the lambda calculus when the author brought up the subject of "currying", and discussed the "Lambda Calculus Way"™ of writing an addition function built on the concept that functions can only take a single argument. The author showed how to express such a thing in Perl:
    sub add {
my $x = shift;
my $f = sub {
my $y = shift;
return $x + $y;
}
return $f;
}

Groovy supports writing code like this too, so I thought I'd see what I could come up with in Groovy syntax. Here's the beast:
    def add (x) {
return {
y -> return x + y
}
}

And the test...
    assert 7 == add(3)(4) // whew.

If there's a Groovy expert out there reading this blog, let me know if there's a better way. All right, back to the essay...

Wednesday, July 04, 2007

Non-Static Members and Static Contexts

A question commonly asked on Java forums concerns an error message similar to the following:

non-static variable cannot be referenced from a static context

In Java, static means "something pertaining to an object class". Often, the term class is substituted for static, as in "class method" or "class variable." Non-static, on the other hand, means "something pertaining to an actual instance of an object. Similarly, the term instance is often substituted for non-static, as in "instance method" or "instance variable."

The error comes about because static members (methods, variables, classes, etc.) don't require an instance of the object to be accessed; they belong to the class. But a non-static member belongs to an instance -- an individual object. There's no way in a static context to know which instance's variable to use or method to call. Indeed, there may not be any instances at all! Thus, the compiler happily tells you that you can't access an instance member (non-static) from a class context (static).

Monday, June 25, 2007

Java Strings and Hash Codes

The question often arises as to how Java can use String values in switch/case statements; e.g.:
switch(s) {
case "Foo": doSomething(); break;
case "Bar": doSomethingElse(); break;
}
The short answer is that one can't. In Java (versions before 5), the expression evaluated in the switch statement must be a char, byte, short, or int. With auto-unboxing and the new enum capabilities of Java 5 and later versions, switch expression may also include Character, Byte, Short, Integer, or enum types. Furthermore, every case expression must be assignable to the same type as what is declared in the switch statement. This means that if your switch statement is an int type, your case statements can be int types, byte types, short types, etc. If, on the other hand, your switch statement is a byte type, the compiler will bark if you try to use an int type in a case expression. In short, however, switch statements with String types (and any type not mentioned above) are simply not available in Java.

Back to the problem of using String values... Every so often, someone will suggest using the string's hash code (an int value) as the value to use as a switch. There are a couple problems with this idea. First, the case expressions must be constant, meaning that the compiler isn't going to accept the result of hashCode() as a valid case. Second, and perhaps a more fundamental issue, string hash codes aren't guaranteed to be unique. Far from it, in fact. The only thing string hash codes guarantee is that strings with different hash codes are guaranteed to be not equal.

So, what is an appropriate solution? It all depends on the design, of course. Most likely, using enums would be a fair approach. In his seminal book Refactoring, Martin Fowler recommends looking at polymorphism for a more object-oriented design. And if one must have switchy strings in a Java-ish environment, there is always Groovy...

~

Thursday, June 21, 2007

Final Variables and Anonymous Inner Classes

Anonymous inner classes require final variables because of the way they are implemented in Java. An anonymous inner class (AIC) uses local variables by creating a private instance field which holds a copy of the value of the local variable. The inner class isn't actually using the local variable, but a copy. It should be fairly obvious at this point that a "Bad Thing"™ can happen if either the original value or the copied value changes; there will be some unexpected data synchronization problems. In order to prevent this kind of problem, Java requires you to mark local variables that will be used by the AIC as final (i.e., unchangeable). This guarantees that the inner class' copies of local variables will always match the actual values.

~