Wednesday, September 30, 2009

Python to Java

Beware, this kind of degenerates into rambling...

I'm learning Java because I got fed up with Python's idiotic garbage collection and my failed attempts to work around it. I liked the idea of using a language with a VM that can run in a browser, and for some reason didn't feel like going the Flash route.

There are some big annoyances which I kind of expected because Java seems to be pretty well hated on the Internet. It doesn't like it when I try to inject little bits of duck typing into its strongly typed system, and its exception handling, well, it reminds me of the first thing that happens when a C programmer sits down with Python or a dynamically typed language for the first time. It doesn't understand that it's okay to have errors at runtime, that a compile-time safety net usually gets in the way more than it helps, and that the programmer should only need to catch exceptions if they want to. The Eclipse auto-solution-finder-thing even lets you put in try/catch blocks that are just two shakes away from how Python does it anyways; print a stack trace and hope it wasn't a fatal error. Go ahead, clog up my code with a boilerplate solution.

Java seems to only give me two options; break out a big, ugly try/catch block when I don't really want to write handling logic anyways, or eternally pass the buck (and force me to import obscure packages) with the "throws" directive. Is there any way of telling Java "if this code throws an exception just crap out, it's okay" without having to type out a ton of syntax?

Java is also too stupid to cast from a Double to a Float (which are proper java Objects, not to be confused with the simple double and float types), and the lack of duck typing is forcing me to write a silly converter function from JSON objects to HashMaps. I can understand this latter case, a JSON object and a HashMap might allocate memory differently even though they share the same get/put interface, but the former case is just silly.

Look at this crap I wrote in my converter:

try {
Object value = json.get(key);
if (value instanceof Number) value = Float.valueOf(value.toString());
hash.put(key, value);
} catch (JSONException e) {
// TODO Auto-generated catch block

I'm just brutally forcing anything that looks like a number in my JSON data to become a float, and since value is an Object I can't cast directly to Float, no, I've got to do stupid shit like this. I'm lucky I am only doing this conversion at init time since I don't expect to load JSON data on-the-fly.

For all this bitching I do it's still interesting to work with another language, and the half-assed attempts at duck typing (the Object type) lets me do hand-waving where in C++ I would need to play type nanny. I definitely like it more than C++, it feels like it's actually been engineered to some degree instead of thrown together, even if it's at times over-engineered or the most obvious, it's-right-80%-of-the-time solution is thrown out for the super-perfect-right-100%-of-the-time solution. It's also a really fast language (compared to Python) and the garbage collection actually does the job.

In Python, it's so painfully easy to make tons of references to an object, many of them circular. I wrote a "smite" method for the vaquum game that programmatically tries to remove circular references. It only partially works, I put a debug message in the __del__ method of an object and it doesn't seem to trigger. I will experiment with a more complex method using the gc module, where I try to make sense of the gc.get_referrers() output and delete every last freaking reference to a given object. If it actually works I'll be doing the Python community a favor, everything I can find online about fixing circular references are way too simple and don't give you an idea of A) how to remove these references from a big piece of existing code and B) how to avoid making these references in the first place without compromising the power of your code. My original method was to immediately make a weakproxy of an object and only allow the rest of the game to see this weakproxy. The original reference is tucked away in some manually-managed list in the master Model object. This worked decently well for Hard Aether, but it's not working for Vaquum. I think it's because my __init__ methods for objects are making too many references to other objects and I'm going to need to export all of that out into a manually-called 'init' function which I call from the weakproxy after its creation.

It is kind of dumb when the easiest method to manage your objects uses an stdlib module. I don't expect much from a language that, before version 2.5, would never free memory back to the OS. I realized while making Hard Aether that Guido really did use Python at first as a super scripting language, it's only in the past few years that anyone has thought of using the language for programs that constantly create hundreds of objects and need to run for as long as the user wants it to.

1 comment:

  1. Java? How very 90s of you. Java running in the browser is a myth. I wonder waht the install base for a working Java VM in the browser is, but I'd be surprised if it's half of what Flash has. Most people have less reason to install Java than Flash or even Silverlight (not that I'd ever advocate that).

    I have recently been informed that Common Lisp and Scheme are where it's really at. And I'm extremely tempted to stick them into a project.