The Artima Developer Community
Sponsored Link

Java Buzz Forum
Getting closure on inner classes

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Norman Richards

Posts: 396
Nickname: orb
Registered: Jun, 2003

Norman Richards is co-author of XDoclet in Action
Getting closure on inner classes Posted: Oct 29, 2007 11:14 PM
Reply to this message Reply

This post originated from an RSS feed registered with Java Buzz by Norman Richards.
Original Post: Getting closure on inner classes
Feed Title: Orb [norman richards]
Feed URL: http://members.capmac.org/~orb/blog.cgi/tech/java?flav=rss
Feed Description: Monkey number 312,978,199
Latest Java Buzz Posts
Latest Java Buzz Posts by Norman Richards
Latest Posts From Orb [norman richards]

Advertisement

On the most recent episode of The Stack Trace, Sam and I talked a bit about Java inner classes and how I solved a long-time problem I've had with trying to pass information out of a Java inner class. This can be rather hard, because inner classes really only for a very weak closure around their scope. The closure over the enclosing method (input parameters, local variables) is essentially read-only. Only final variables can be closed over, and final variables cannot be changed. The object referred to can be mutable, but the enclosing scope can never see a new object. For example:

public void myMethod() {
    String x = "original value"; // must be final

    new Runnable() {
        public void run() {
            x = "new value";  // but if it were, we couldn't do this
        }
    }.run();

    System.out.println("The value is " + x);
}

This is not valid in Java. The way inner classes are implemented, the Object that x refers to is basically passed by value into the object behind the scenes, and the inner class itself has a new field that just happens to be called x and just happens to point to the same object the outer x does. If the implementation doesn't have any link to the variable named x, there's no way to change the value. Thus, we have the infamous decision that made inner classes only able to close over final variables. If you make all the cases where your weak implementation doesn't work invalid, then your weak implementation works - Q.E.D.

(side note: in the special case of strings, the Java compiler actually optimizes the code by placing the String value in the constant pool of the inner class and doesn't actually pass it in. But in the general case, the description is correct)

The problem here is similar to the swap problem. In Java you can't write a swap function with side effects. In C++, it's trivial to do by passing references around:

void swap(int &x, int &y) {
  int tmp = x;
  x = y;
  y = x;
}

Java doesn't have the notion of being able change the value a variable points to by passing a reference to it along. However, it is obviously possible to get a similar effect in Java using a wrapper class.

public class Reference<T> {
    T value;
    public SimpleReference() { }
    public SimpleReference(T value) {
        setValue(value);
    }
    public T getValue() { 
        return value; 
    }
    public void setValue(T value) {
        this.value = value;
    }
}

Going back to the inner class example, we could then write something like the following. It's not beautiful, but Java generics make it relatively palatable. Conceptually it's not any different than thinking to pass an object pointer along.

public void myMethod() {
    Reference<String> x = new Reference<String>("original value");

    new Runnable() {
        public void run() {
            x.setValue("new value");
        }
    }.run();

    System.out.println("The value is " + x.getValue());
}

It really got me thinking though. Why doesn't the compiler just do that for me automatically? The compiler knows what variable in the enclosing scope need to be a part of the closure. It has to verify that they are all final. There's no reason that instead of checking that they are final that it couldn't wrapper all of them with a Reference object, calling getValue()/setValue() as necessary. The code would then read identically as the first Java example above, and inner classes would have had a much more interesting form of closure than they do now.

If you are concerned about too much magic behind the scenes, keep in mind that inner classes already can add a number of synthetic fields/methods to your classes as is. And having a method call behind the scenes is not really any different that a construct like Foo.class which generates bytecode to call Class.forName(). It may be too much magic for the Java 1.1 days, but by today's standards it's not the least bit wild. Think about what goes on behind the scenes for an enhanced for loop.

A couple final points. First, I'm sure the language designers could come up with a more interesting way to get a more powerful form of closures into inner classes. I'm just saying that it looks like there was at least one incredibly trivial implementation option available.

Second, I do realize that even if inner classes had a more complete closure, that doesn't really address all the things people want today. People want closures that don't feel like separate classes and that can be used to implement interesting control structures. Real blocks with closures would (we hope) also have much better syntax than inner classes do now. Nonetheless, I think it would still have been significantly better than what we have now.

Finally, I'm sure I'm not the first person to do this. However, I've never seen this technique before, and I have done quite a bit of searching to find solutions. It's nothing spectacular, but it did solve a very big problem I've had for years. I hope it helps someone else out there.

Read: Getting closure on inner classes

Topic: Red-banded Hairstreak Previous Topic   Next Topic Topic: How To Display / Delete IP Route Cache on Linux

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use