Published September 9th, 2007 Java , Programming 1 Comment
Now that Java is open source and all that, everyone is up for adding new features to the language that Sun never got around to adding. Things like named arguments, closures, and properties are what interest me most. Unfortunately, I find myself disagreeing with most of what is being said. Most of the ideas start with a fairly simple and easily overcome problem, a fairly complex solution, then begin tacking on as many “It would be cool if…” or “… just like Ruby” ideas as possible.
Named arguments seem pretty cool, and they do make a few cases fairly readable, like in String.replace(), and many other ambiguous instances where two arguments are similar looking but very different in function. Unfortunately though, when you start applying it to more complicated cases, it just breaks down into overly-complicated methods. For instance, here’s an example from JGP code:
GraphicsOutput gout = game.getGraphicsOutput();
gout.setColor(JGPColor.makeFloat(1,1,1));
gout.setTranslate(30, 30);
gout.setRotation(20);
gout.drawRect(-10, -10, 20, 20);
Now, named arguments might’ve made this code look something like this:
GraphicsOutput gout = game.getGraphicsOutput();
gout.drawRect(x: -10, y: -10, width: 20, height: 20, translatex: 30, translatey: 30, rotation: 20);
It’s definitely shorter, and probably about as readable (maybe with the exception of translatex and translatey). But heres how it looks on the GraphicsOutput side:
public void drawRect(float x : 0, float y : 0, float width : 0, float height :0, float translatex : 0, float translatey : 0, float scalex : 1, float scaley : 1, float rotation : 0) {
// do something with all those values….. mind numbing
}
It gets better when I decide to add support for lines of lengths other than 1. Now, every single line related function needs another argument added to that already huge list. And if I happen to forget it somewhere, I won’t ever notice until I attempt to use it in a function call, because it’ll act just like a default value would.
Named arguments definitely look good when you’ve got single purpose classes with single purpose methods, but for anything more complex, they become cumbersome and brittle. Methods become far too complex; in this case, my drawRect function would need to contain all of the code needed to set all of those values in OpenGL, or call a private utility function to do it (and remember to pass all of the correct arguments to it). I think your better off just memorizing the ambiguous cases and making more complicated cases into state machines or parameter objects.
Next on the agenda is closures. I’ve been meaning to learn more about functional programming, but so far I’m pretty much useless on the subject. I might be completely off the mark on this one, but heres my thoughts anyway.
I’ve used them before in Perl to achieve cleverness, but I’ve yet to really see a point to them besides cleverness. It looks good when paired with methods that take a Runnable, but the complications it would introduce into the language are probably not worth it. I mean, I’m no expert or anything, but it seems to me like the whole reason why variables used in anonymous inner classes must be final is because the JVM doesn’t have any way to cause those variables to “live” past the end of the function. When the compiler makes the inner classes, its just copying the variables into the new class. If they weren’t final, changing them wouldn’t affect the inner class. I’m sure they’d love to had made it so you don’t have to sprinkle final everywhere for things to work, which would also have made closures a very simple thing to implement. But the fact that they didn’t leads me to think people are underestimating the difficulty of making closures happen.
Don’t even begin to think about how to JIT such a beast. Ok, I did. You’d need to analyze which values in a method are used by closures, and allocate them outside of the stack and reference them, separate from other variables, through a pointer. You’d then give the pointer to the closure, and use reference counting from within the body of the method making the closure and from within the closure’s finalizer to determine when to free it. Not trivial, but I guess not as painfully difficult as I thought.
Finally, properties. These, I think, are a good idea. I personally would just like to implement an automatic getter/setter invocation syntax with the good ol’ dot syntax, like so:
public class Test {
private int val;
private NotifyObject not;
public int getVal() { return val; }
public void setVal(int val) {
this.val = val;
not.valChanged(val);
}
}
Test t = new Test();
t.val = 6;
System.out.println(”Val: ” + t.val);
Looks just as nice a public variable, and in fact has the advantage that you could easily switch from public variables to getters and setters without breaking other code. (You’d still have to recompile it, though). This is the main reason people don’t use public variables in the first place; you must be 100% positive you’ll never need a getter or setter on that variable. It also would allow for an extremely smooth migration, as most of existing Java code has getters and setters (whether needed or not), and now you can seamlessly use them as if they had properties. Maybe some syntactic sugar would be nice to aid in creating the getters and setters, but most IDEs can already write them automatically. And it has a certain visual clarity that I’ve grown to like.
Well, there you have it, my take on a few Java 7 features.
Ruby is cool.
Java doesn't need to be cool to be useful.
Java doesn't need to be Ruby to be useful.
QFT.