picture home | pixelblog | qt_tools

omino code blog

We need code. Lots of code.
entries for category "java"
David Van Brink // Fri 2007.05.25 19:31 // {java}

Java Source versus Binary Compatibility

This post shall be just a short note on an observed Java behavior… I learned it by breaking something.

Part of my current job involves creating and maintaining a couple of public API’s. We’re still working out all the rules and policy as to what, exactly, must be compatible with what. For now, each release of our product includes a full install, so we can, in principle, change anything we want as long as it’s all self consistent.

In practice, however, various individuals and groups are writing code against these API’s, and may or may not be enthusiastic to change their code based on my whimsies. But at least their code gets rebuilt automatically.

In the future, we expect third parties to write plugins to our product against our API’s. When they start doing that, we’ll have to be both API and binary backwards-compatible. Or at least consider carefully who we will alienate if we break their plugins.

Ok. So consider the following simple API. Let’s call this our “platform”, and it consists of three Java classes, like so.

package sa.api;
public class Animal{/**/}
package sa.api;
public class AquaticAnimal extends Animal{/**/}
package sa.api;
public class Utils
{
    public static Animal getIt() { return null; }
}

Next, consider some client code. I’ve called it a “plugin” but really, it’s any code that you expect to link against the “platform” above.

package sa.plugin;
import sa.api.Animal;
import sa.api.Utils;
public class Plugin
{
    public static Animal getAnimal()
    {
        Animal a = Utils.getIt();
        return a;
    }
}

All very simple. This code works just fine. Now here’s the fun part. We’re doing Rev 2 of our API, and we realize that in every case of Utils.getIt(), as it turns out, we’re returning not just an Animal, but an AquaticAnimal. So, we change the method return value, like so:

package sa.api;
public class Utils
{
    // We used to return Animal, 
    // but since it's assignable,
    // we think this change is safe.
    // dvb07, rev2
    public static AquaticAnimal getIt() 
        { return null; }
}

Sourcecode-wise, this change is fine! Our existing line Animal a = Utils.getIt(); still compiles, since AquaticAnimal “is a” Animal. It’s all legal.

But.

Our old copy of Plugin.jar, the one that was built against the original version, has problems. You see, the compiled code stores the whole signature of its methods including return types! When we load our old jar against the rev-2 platform, we get the following error:

java.lang.NoSuchMethodError: sa.api.Utils.getIt()Lsa/api/Animal;

Conclusions
Recreating the above error in a controlled situation, to write this entry, was a bit tricky! Initially I had Animal and AquaticAnimal as static inner classes of Utils, and I couldn’t get the error to happen. And creating this error in isolation requires a bit of handiness with Jar building and executing. I did it all in Eclipse with a supercharged class loader, but it was still tricky to induce.

If you need to maintain binary compatibility, you can think hard about it, try to do things which seem “safe”… but the only way you’ll really know is if you keep around actual compiled code and test it against your revised API regularly.

Significantly: Checking against source code is not sufficient! The source code gets some benefit during recompilation.

It seems so obvious, but there y’have it. Back to the debugging, go I!

1 comments
Douglas // Sun 2007.06.10 07:467:46 am

I believe this is why the Java class library writers deprecate APIs and write new methods that parallel old ones.

oh, i dont know. what do you think?


David Van Brink // Mon 2006.12.11 13:14 // {java scripting}

Java 6, JavaScript

Java 6 is now available. There’s just one feature that caught my eye: JSR 223, support for JVM-based scripting languages.

Now, of course, that’s all wonderful, and they’ve got this full infrastructure to plug in any number of scriptable languages via a ScriptEngineFactory and that there’s all sorts of compliant languages that might be available… I’m sure it’s all quite fascinating.

The only thing I care about, though, is that, hooray, they include exactly one scripting language as standard in the JRE: EcmaScript, implemented by Rhino.

Now, of course, that’s all wonderful, and gives you the opportunity to add scripting to your application, oh how very moderne, obedy dobedy do and so fothe. But check out this super simple exciting usage! Forget all the power and generality, here’s a simple trick that solves a real problem that I bet you’ve had occasionally: simple text-based expression evaluation. Yeeha!

public static void main(String[] args) {
  RhinoScriptEngine e = new RhinoScriptEngine();
  try
  {
    Object o = e.eval("a = 24; b = 11; Math.sin(a) + b;");
    Console.print("result: " + o + " (" + o.getClass().getName() + ")");
  } catch (ScriptException e1)
  {
      // (probably a syntax error in your expression)
      e1.printStackTrace();
  }
}

Produces the following output:

   result: 10.094421637993376 (java.lang.Double)

Joy!

1 comments
Douglas // Tue 2006.12.12 23:5711:57 pm

Hey, that’s cool!

oh, i dont know. what do you think?


David Van Brink // Sat 2006.10.14 07:18 // {java levity people}

The Menu

The other day I was coding. I wasn’t sure if it was afternoon or maybe evening… A single ray of red sunglight (dusk? dawn?) somehow found its way to a patch above my ergonomic chair. And my computer was strange. I had to put scrabble letters and plastic fish onto the screen just right, but they kept falling down. Also, my desk was sloped so the keyboard and mouse kept falling heavily into my lap, if I wasn’t careful to keep holding them up.

I looked around the office, and all my coworkers were happily, frantically typing away. And also, putting scrabble letters onto their screens, and sometimes reaching into the screen to squishily adjust something or other. Far away someone shouted, “101100101!” and was rewarded with scattered polite chuckles.

They were all very old.

I asked, “Should you still be here?”

“Oh yes! We have much work to do! We’re the only ones who understand the Olden Code!” He certainly seemed enthusiastic. “You know, job security, ha ha! In fact, this year I think we’ll be able to add a feature!”

“Yes, yes, a feature!” offered another in a nearby cube.

“But… should you still be here?”

A voice from a yet different cube answered, though he too didn’t turn to look. “Of course! We can’t leave. No no! We owe the Company. But that’s ok! It’s warm here.”

“And we have frozen burritos!” a fourth added.

“I was almost paid off,” another voice contributed, from a row or two over, “but then we got more users, so I had to stay on. Successful product, say what!”

More conversation ensued in this odd fashion, voices chirping from nearby cubes. But I didn’t understand. I wandered the aisles. One cube was decorated with a collection of old action figures, another with tiny bicycles, another with foam palm trees. And then I saw, posted in the break room, The Menu.


Fixed-Priced Items
(These are billed to you just once, regardless of software deployment volume)

  • Using goto: $0.01 per use
  • Using continue: $0.02 per use
  • Extending a class: $1.00
  • Extending an interface: $2.00
  • Extending Vector: $50.00
  • Public static variable: $100 each
  • Reading environment variable: $100 each
  • Duplicated source code file: $1000


Variable-Priced Items
(These items are billed per event on your user’s computer.)

  • Writing a file from the File menu: Free
  • Writing a text file: $0.50
  • Writing a binary file: $5.00
  • Writing a “dot” file: $15.00
  • Writing any file in $HOME: $20.00
  • Cost for file size during installation: $0.0001 per gigabyte
  • Modal dialog with two choices: $0.50
  • Modal dialog with one choice: $1.00
  • User enters illegal value: $10.00
  • Spawning a thread (application): $0.01
  • Spawning a thread (library): $0.99
  • Launching a subprocess: $1.00
  • Launching a Perl subprocess: $10.00
  • Launching a Cygwin subprocess: Two Months’ Salary


Happy Coding! :-) :-) :-)
The Company Needs You!

I was terrified. I would be discovered, and I’d be billed. I knew I’d done all these things. And then I thought, well, it is warm in here… it’s better than being outside, in the rain, without a burrito.

oh, i dont know. what do you think?


David Van Brink // Fri 2006.10.6 20:55 // {java}

Safety Java
or
Asterisk Considered Harmful

The Phone Call

Me: Did you use the app Jar file from the build?
Them: No… just sync’ed out of your repository and built it manually with javac.
Me: Were you using all the files from the correct branch?
Them: Oh yes, got the app sources from the main branch. Oh… we used the libraries from the other branch, but we only needed the app jar and it seemed to build fine.
Me: (Stunned. Surely they can’t expect that to work reliably.)
Me: (Moment of revelation. Brain melts and reforms in new configuration.)
Me: That should be fine.

C: Link-fragile

Now, I’m just a simple procedural guy. I like to write my subroutines and use ’em. Java? Yeah, yeah, ‘course I like it, I don’t have to say malloc() and free(). Great stuff.

But gradually I’m realizing just how profoundly different are Java and C.

In C, you don’t just compile a file and expect it to be “fine”. You have to compile and link your whole project with appropriately matching compiler settings, up-to-date header files… all kinds of things can go wrong in the link.

Consider these two C files, a header and a function:

// file: foo.h
typedef struct FooStruct {
    int k[100];
} FooStruct;
// file: bar.c
#include "foo.h"
fooStruct *makeFoo(void) {
    fooStruct *result = (fooStruct)calloc(1,sizeof(fooStruct));
    return fooStruct;
}

The object code for bar.c is influenced by the struct size from foo.h. If you change foo.h, you must recompile bar.c.

Java: Link-ignorant

I did an experiment, with the following two Java classes.

public class Referring {
        public static Object returnForward()	{
            return ReferredTo.getValue1();
    }
}
public class ReferredTo {
	public static Boolean getValue1()
	{
		return false;
	}
}

It turns out that the identical binary is produced if you change the type of ReferredTo .getValue1 to Integer, or Map, or File… the method Referring.returnForward doesn’t care what it’s getting. It can even return a primitive, like int.

My guess is that Java resolves method invocations by name at run-time. If rigorously true, then it should be possible to compile Java code without any of the classes that it uses and imports. I suspect that the requirement of having appropriate source code or Jars to compile against at all is a concession to good taste (or a prevailing C-ness of attitude at some point in its past, if you prefer).

As a thought experiment, it’s clear that you could implement any functionality you want using only reflection at run-time, assuming you knew the full package and class names for any methods you wanted. Class.forName() and you’re so dynamic.

And indeed, Jython (a Java implementation of a Python interpreter) and Rhino (a Java implementation of an EcmaScript interpreter) both do exactly that.

But I’m glad that the compile-time checking does happen! It means that you can compile against any old Jar files and — if the compile succeeds at all — that the binary class is going to be good and proper and the same one I’d get from the same source file.

Almost.

The Asterisk Considered Harmful

Now, consider this source code:

import AlsLibrary.*;
import BobsLibrary.*;
public class Reporter {
	public static int getUtilValue()
	{
		return Util.getUtilValue();
	}
}

That’s great. Presumably the class Util exists in AlsLibrary or BobsLibrary. It can’t be in both: The Java compiler will warn you about that with the message: “reference to Util is ambiguous, both class BobsLibrary.Util in BobsLibrary and class AlsLibrary.Util in AlsLibrary match“.

If the method getUtilValue is in AlsLibrary, we get binary something like, if you’ll pardon my psuedobinary:

getUtilValue: return findbyname("AlsLibrary.Util.getUtilValue").invoke();

And now, the punch line. Oh, but this is rich.

Suppose that we used to have Util in AlsLibrary, but then (after interminable meetings) we move it to BobsLibrary. The identical source code will still compile, but produce a different binary. We’ve finally tricked the compiler, with our import-wildcard!

The generated class will fail at run-time with a class-not-found exception.

This would have been avoided if the source code read:

import AlsLibrary.Util;
import BobsLibrary.Application;
public class Reporter {
	public static int getUtilValue()
	{
		return Util.getUtilValue();
	}
}

The Phone Call v2.0

Them: Hey aah, we tried to build but it says that Util can’t be found…
Me: Oh, yeah, we moved it into BobsLibrary. Get the latest of everything and it’ll be fine.
Them: Oh, thank you for breaking us again! Gosh, at least we found out at compile-time instead of run-time!

So remember:

Don’t import with asterisk!

P.S. If you know of other hazards where changes external to the source Java file can affect the generated class file, I’d be interested to hear about them.

1 comments
Douglas Jones // Tue 2006.10.10 16:194:19 pm

A long time I learned to be explicit in my imports not just for that reason, but because I could tell what I was dealing with when I read the code. My co-worker thought it was silly obsessive behavior until he ran into a problem like the one you illustrated and it took him considerable time to hunt down the cause in the very large project. Afterwards he converted ever place he used * and was explicit in his imports from then on.

oh, i dont know. what do you think?


David Van Brink // Sat 2006.09.30 11:24 // {code java software architecture}

A Philosophical Snapshot

Introduction

This introduction has been written last.

The intent of this post is to give a snapshot of some coding strategies which I think are good ideas, today. This is of course reflective on the most recent round of development I’ve been involved in. Reading it over, I see that the notions are drawn nearly equally from things we got right, and things that (I believe) we got wrong.

This is my blog and my essay, so I’ll just make these statements as if they are indisputable truths from on high. Sometimes I’ll even try to support them. But I certainly encourage dispute and counterexamples. Comment away!

These are all, broadly, under the heading of API design. After all, what isn’t?

These are also all referring to Java code, though the principles are certainly true in any programming language. Says me.

Offer Power, Not Rules

Make it easy to do the “right” thing. Do not try to make it “impossible to do the wrong thing”. Building your API around “restrictions” rather than “capabilities” invariably results in a cockeyed underlying implementation, infusing anachronistic domain-specifics into inappropriate places. It also can lead towards untestability. For testing you, by definition, need to exercise the functionality “out of context”.

Provisions For The Journey

Consider the entire development flow, not just the final result. (Sometime in the 1970’s Japanese cars all included easily-located jacklift- and tow-points on the frame. American cars still sucked.) For example, if generated code is part of your product, it is an obstacle to quick debugging turnaround times in Eclipse. Consider that as part of the cost. It may be the right solution, still, but is worth considering. Similarly, if your code relies on certain files in certain places, or certain parts which must exist as Jar files, that will have implications to your clients’ interactive development.

Obligations Versus Offerings

  • Obligations are Abstract

Any kind of “plug-in” that your product supports will necessarily have multiple implementations. The thing which unifies the different implementations is that they each satisfy some fixed minimal set of “obligations”.

In Java, a useful way to manage these obligations is by an interface.

If you change the interface, you are changing the obligations. (You can also change the obligations by merely reinterpreting the interface, but let’s gloss over that for now.) Changing the obligations of a plug-in is a serious gesture. Managing that interface carefully is important because any change can have broad effects. A committee of interested parties can be beneficial in restricting unnecessary change.

Once an interface is “out the door”, that is, used by a broad base of implementers, the cost of changing it increases enormously. In general, changing an existing interface (once “out the door”) is impossible, and a better choice is to create a new one, while still supporting the old.

  • Offerings are Concrete

Conversely, a utility library provides a set of features, or “offerings”. Like a plug-in interface, many developers depend on it. However, it is perfectly safe to increase its feature set, as long as the existing features remain unperturbed. Also, in contrast to plug-ins, there will be just one implementation.

In Java, the best way to express offerings is with a concrete class.

The maintainer of a utility library can certainly benefit from client-feedback, but restricting change should not be the primary goal of that feedback. Rather, the client-base should make clear how they are using it and what additional features are desired. The maintainer can then factor that all together to satisfy his clients appropriately.

While it is true that one way to maintain compatibility is to prohibit change of the library, a better way is to ensure that existing features remain operational. This can be done by unit tests. Clients should be free to add unit tests to guarantee that their particular usages remain supported.

If the maintainer inadvertently alters existing behavior such that a client expectation is changed, they can either a) strive to retain the existing behavior or b) negotiate the change with the client.

As with plug-ins, once a utility library is “out the door” the cost of changing it increases significantly. In fact, we can then state clearly that “changing it” is “breaking it”, and one must consider carefully before doing that. (Although occasionally it is still the right thing to do.)

But, unlike “obligations”, it is always safe to add more “offerings”. The next release of the utility library may do more, but never less.

On Plug-Ins and Privacy

This next one is subtle.

A “plug-in” is something that will have multiple or numerous implementations. A “plug-in client” is something that uses a particular kind of plug-in.

A plug-in client obviously must depend on a particular interface for the plug-ins it uses. A plug-in may depend on a certain usage-model or flow. That is, it may expect to be invoked in certain ways. Ideally, this is well-documented, but if not, then the first plug-in client more or less defines it. But, a plug-in must not depend on a particular plug-in client. The classic symptom of this an API like:

public interface IFooPlugIn
{
    public void setX(int x);
    public int getX();
    public FooRecord generateKung();
    /**
     * To invoke sub-plug-ins, we have to give each plug-in a
     * reference to the application.
     */
    public void setApplicationHandle(JoesFirstApplication applicationHandle);
    // Whoops!

}

OK. Right now, you’re all about Joe’s Application. It’s the biggest thing in the world, and the whole company is behind it. Joe’s Application is going to increase shareholder value, and that’s great.

But this API locks you into emulating JoesFirstApplication when you someday (I know you can’t imagine it now) want to write a different application that leverages all those existing plug-ins. Half the value of plug-ins is lost if you’re not decoupled from the client. If there’s some aspect of the client that your plug-in needs, it’s better to create the smallest possible interface which provides it, and pass that instead:

public interface IFooPlugIn
{
    public void setX(int x);
    public int getX();
    public FooRecord generateKung();
    /**
     * Minimal access to discover sub-plug-ins.
     * Clients: your implementation
     * of IPlugInFinder determines the available scope.
     * Plug-in authors: use this to find legally 
     * accessible sub-plug-ins
     */
    public void setPlugInFinder(IPlugInFinder plugInFinder);
}

There. Now we’ve left the door open to create a completely different client that can leverage a body of existing plug-ins. We’re not locked into Joe’s vision forever. You know… just in case JoesFirstApplication isn’t the final manifestation of your product.

Conclusion

I hope, in the future, to look back at this post and think, Good heavens, that’s so basic that you shouldn’t even have to say it! Equally likely, future-dvb will say, What a bunch of misguided nonsense. Only time will tell.

oh, i dont know. what do you think?


Read part one first, please!

Bad Code
The experience of Bad Code comes from the following dissonance:

  • You want to use this code, either as a library or perhaps to improve or fix it. (In some settings it may be that you have to use it.)
  • It resists being used.

In extreme cases, a body of source code doesn’t build. But even if it does, if you can’t discover a way to use it then it has become Bad Code.

I believe there’s two things which contribute the most vigorously to the badness of Bad Code. I’ll enumerate these, and then offer a speculation on how this comes about.

Badness 1: No Examples
Examples can come in many forms. For something downloaded from the interwebs it might be a folder named “Examples”. Nothing wrong with that.

But if it’s a library from the guy in the next cube, it might just be an email with some stuff pasted in, or even some whiteboard scribblings. Remember, I said Good Code lets you get something done in 20 minutes. Talking to the author isn’t “cheating”.

Also, as I’ve previously babbled, unit tests are great. This is another place where an example might be found.

But the key point here is that there are examples of use. And you can find them.

Badness 2: External Dependencies
Here is a recurring property of Bad Code: it depends on everything else being “just right.” That may mean that lots of other libraries have to be in place in some nonobvious way, or that files have to be in certain spots, or that environment or property variables have to be just so. And the perp will innocently say: “But why would you ever run it without all the other stuff?”

Because, my friend, that’s what makes Good Code good.

How Does This Happen?
In my recent experience, this comes about just one way: programmers following a spec.

I know it sounds crazy… but I’ll attempt to explain it in abstract pretty pictures. Here’s a spec, derived from some whiteboard discussions and some anecdotal customer feedback:

And here is the Bad Code implementation of that spec:

It looks just like the spec! Right down to every little kink and error. Of course you can’t use it for something in 20 minutes. Your product took years to develop, and this implementation knows every nook and cranny of that work and depends upon it.

And here’s my vague and unsupportable visualization of the Good Code implementation:

The spec has been deconstructed into a rational architecture. The implementation includes the spec but is not damaged by the spec. Ah, if only pretty pictures could actually be true…

Make It Look Easy
In part one I presented the Mozilla Rhino interpreter as an example of Good Code. It was self-contained and had examples, and was relatively easy to set up and run. And one could say, “Oh but that was a particularly easy case. Of course it can run standalone!” The trick is to make it look easy.

There’s an artist/mathematician named Scott Kim who is known for creating “inversions,” text art like this:


It has 180 degree rotational symmetry. A wise person once pointed out to me that, “Each of Kim’s inversions looks like it was a particularly easy one, don’t you think?” There’s always some little thing that makes it trivial. But it’s not. The trick is to make it look easy.

If it doesn’t look easy, you haven’t worked hard enough.

That’s the art.

In part three I’ll offer a couple of tips that might, just might make your code usable by someone, for example, me, in twenty minutes.

2 comments
Douglas Jones // Thu 2006.09.7 07:457:45 am

That reminds me of a quote I heard about 10 years ago. “If you can’t explain it clearly then you don’t understand it well enough.”

David Van Brink // Thu 2006.09.7 14:522:52 pm

I agree with that!

Though… the implicit full claim would be: “If you can’t explain it clearly then you don’t understand it well enough for me to understand it.” Some people are very comfortable with complexity and transverbal software… but I don’t want to inherit their code… if their comfort level exceeds mine.

Yet another humorous retelling of approximately the same thing: http://www.gnu.org/fun/jokes/pasta.code.html.

Nearly every software professional has heard the term spaghetti code as a pejorative description for complicated, difficult to understand, and impossible to maintain, software. However, many people may not know the other two elements of the complete Pasta Theory of Software.
Lasagna code is used to describe software that has a simple, understandable, and layered structure. Lasagna code, although structured, is unfortunately monolithic and not easy to modify. An attempt to change one layer conceptually simple, is often very difficult in actual practice.
The ideal software structure is one having components that are small and loosely coupled; this ideal structure is called ravioli code. In ravioli code, each of the components, or objects, is a package containing some meat or other nourishment for the system; any component can be modified or replaced without significantly affecting other components.
We need to go beyond the condemnation of spaghetti code to the active encouragement of ravioli code.
— Raymond J. Rubey

The problem is that we each of us can read these sentiments and think, Oh yes, of course I do that!

oh, i dont know. what do you think?


Well, I’ve been holed up in my dank apartment these last 3 weeks, canvas and plastic stapled over all the windows. I’ve been writing furiously. Red-pencil scribbles cover tablet after yellow Big Chief writing tablet with my profound wisdom and observations. I feel myself following in a great tradition… Dear reader, allow me to share with you some morsels which you might find entertaining or even informative. This is to be the first of a three part epic on the subject of Bad Code.

Introduction
What makes “Bad Code”? I feel like I’m tormented and dogged by Bad Code. Some of it is my own. Naturally I’m less bothered b my own Bad Code than my other people’s bad code, because I have at least some insight into the perverse intent of the code when it’s my own. But it’s still Bad Code.

What makes Bad Code?

Oh, there’s endless modern kid-stuff about good practices and code smell and all that nonsense. It’s my experience that even good kids who learn all about test-driven development and favoring composition over inheritance and all that rubbish and follow it to the letter still write Bad Code.

What makes Bad Code bad?

First of all, it has to be code. You wouldn’t call it Bad Code if you experience it as an application or tool or whatever. You’d call it a bad app, or a bad web page. I’m talking about Bad Code. You typically experience code in the form of a library that you want to use or source code that you’re called upon to modify.

Here’s my definition of Bad Code: If you can’t load it into your IDE and make it do something interesting under your control in twenty minutes, it’s Bad Code.

Let me justify this first with a counterexample of some Good Code. Oh yes. Cranky am I, but praise is possible.

Some Good Code
One of Mozilla’s open source projects is Rhino, a JavaScript interpreter. (Actually it is officially called ECMAScript now, but whatever.) Why is this Good Code? Let me count the ways:

  1. It’s easy to find: http://mozilla.org/rhino/.
  2. It was easy to download. A full source drop was 1.7M.
  3. Although it wasn’t an Eclipse project, it imported perfectly into Eclipse as a “Java Project from Existing Source” with almost no errors. A fast look reveals that all the errors are in one package implementing XML stuff, and its referring to org.apache.xmlbeans. On a whim, I remove that entire subpackage and apparently nothing else was depending on it.
  4. There is clearly marked “examples” directory…
  5. The examples are named, have a few comments which are enough to get the lay of the land.
  6. I create a blank .java file, and start copying bits and pieces from the example into my new file. Soon, I have a tiny piece of code which I think I understand pretty well, and does something explicable

Here’s some code. I know it’s a bother, but give it a read. It’s short. It would mean a lot to me. And remember — it took me less than 20 minutes to get here.

public class DvbScript {
    public static void main(String args[])
    {
        Context cx = Context.enter();
        try {
            Scriptable scope = cx.initStandardObjects();
            String s;

            s = "var abc = 13/7;";
            cx.evaluateString(scope,s,null,0,null);

            s = "var xyz = Math.sin(1.33) + "*****";";
            cx.evaluateString(scope,s,null,0,null);
            
            Object abc = scope.get("abc",null);
            Object xyz = scope.get("xyz",null);
            System.out.println("abc is " + abc.toString() + " and is a " + abc.getClass().getName());
            System.out.println("xyz is " + xyz.toString() + " and is a " + xyz.getClass().getName());
        } finally {
            Context.exit();
        }
    }
}
Produced this output: abc is 1.8571428571428572 and is a java.lang.Double xyz is 0.9711483779210446***** and is a java.lang.String

In that brief bit of code, I managed to successfully exercise the library and begin to understand the internal scheme of the interpreter.

Why It Was Good
It wasn’t a completely bump-free ride. I had to slice out part of the source code as downloaded… I deleted a whole lobe of the source tree that appeared to be all about XMLBeans or some such. But it was painless. Their one dubious external dependency on org.apache.* was isolated and optional.

The examples were easy to find, and they ran. At first they produced exceptions, but then I read the source code comments and knew what to pass on the command-line and all was well.

Fundamentally, as a user of this library, this Good Code, I felt like I was the target audience. Someone had considered that I would be sitting here today trying to run their stuff.

Now, here’s the thing of it: Bad Code feels the same way. It feels like someone has consciously considered that I, David Van Brink, would one day try to use their stuff, and has premeditated ingenious ways to thwart that goal.

In part two I’ll be cheerfully exposing some of the strategies that Bad Code takes to torment me.

oh, i dont know. what do you think?


David Van Brink // Sun 2006.08.27 22:22 // {java pointless}

A Pointless Applet

full screen

Pointless, and poorly written, too. But shows basic technique for applet animation:

  • Start a thread which updates your model,
  • Call jWhatever.repaint() after each model update,
  • If repainting takes too long, you’ll get more model updates than repaints. Thus is the wonder of threads.

In my Apple ][ youth this is the sort of stuff I mostly wrote: faux-data displays.

4 comments
Daniel Jalkut // Mon 2006.08.28 04:184:18 am

It may be pointless, but I like the aesthetic. And I got caught staring into it, playing “what’s the most intersecting circles I’ve seen so far.”

Douglas Jones // Wed 2006.08.30 22:1610:16 pm

But it looks cool! I’m totally hiring you to make fake computer screens if I ever make a movie that needs them.

Daniel Jalkut // Sat 2006.09.2 13:011:01 pm

I couldn’t stand living without a screensaver version of this, so I ported this code to Cocoa, and produced a Mac OS X Screensaver:

http://www.red-sweater.com/blog/179/subservient-blips

Thanks for the cool code, David!

Red Sweater Blog - Subservient Blips // Sat 2006.09.2 14:092:09 pm

[…] I was pleased by the kind of “cheezy space film” mood David Van Brink’s pointless applet put me in, so I got the wild idea of creating a Mac OS X screen saver out of it. […]

oh, i dont know. what do you think?


David Van Brink // Sat 2006.08.26 19:59 // {code java numbers}

Rationalization Applet

Amazing how easy it is to paste C code into Java. Takes surprisingly few adjustments to work. This applet demonstrates the “Rationalization” algorithm mentioned a post or two earlier.

Note 1: RiverLayout is a fine little LGPL layout manager which made this applet much easier than it would have been with the standard Java layout managers. All of which I hate, by the way. RiverLayout was exceedingly simple to use for this kind of basic stuff.

Note 2: I looked around at various other online math applets and found one thing in common about them all, which I hated, and that was that one had to press a “Compute!” button before the answer would be, aah, computed. So I omitted that antifeature from mine.

5 comments
Daniel Jalkut // Sat 2006.08.26 22:0610:06 pm

Nice work, David. “Compute” buttons are indeed the devil. Most people still don’t get it that computers are super insanemagifiicently faster than we can possibly imagine, and it’s best to just do everything “on the fly” until proven otherwise.

David Van Brink // Sun 2006.08.27 16:194:19 pm

…And, I’m having a hard time thinking of a good “proven otherwise” situation. For example, Eclipse — in contrast to every other IDE I’ve used — initiates syntax checking as you type, and a full build whenever you save your file.

As long as it doesn’t interfere with the the user-interactivity, where’s the harm?

Daniel Jalkut // Mon 2006.08.28 04:154:15 am

That’s exactly right. As long as it doesn’t make the task at hand take longer than the user would like, or steal too much power from the rest of the user’s tasks, then “it’s fine.”

Too many programmers have an unnecessary desire to preserve instruction cycles, as if they were in danger of extinction.

Ryan Ballantyne // Sat 2006.09.2 13:411:41 pm

There are many situations where a “Go” button is desirable. Any operation that takes a significant amount of time should require explicit confirmation to begin. Obviously, simple math does not fall into that category. Complex math, like calculating the mandelbrot set, does (I once wrote a Java applet to do that as part of an intro to programming course. Yes, I gave it a “Calculate” button).

David Van Brink // Sat 2006.09.2 15:073:07 pm

Hi Ryan — I would phrase the requirement vaguely as, “The program should do as much as it can automatically, as long as that doesn’t get in the way of the user.”

And one way I might interpret that for a mandelbrot generator is to, truly, begin calculations immediately for every input action… but halt them immediately, too, if new user input invalidates that work.

Amusingly, in my distant distant past I wrote a Mac program called “MegaBrot” which supported our company’s demo NuBus board which did exactly one thing: used 3 hardware multipliers to compute Mandelbrot iterations. It was fast then, but slower than any computer at CostCo today. I’m pretty sure it had a “Calculate” button, too. :-)

Oh dear… found a usenet posting mentioning it, even. Pardon the digression… your comment triggered a dormant neuron.

oh, i dont know. what do you think?



(c) 2003-2011 omino.com / contact poly@omino.com