I’ve been using this trick for a while and I thought I’d share it. For those who live by Eclipse’s quickfixes, it’s not entirely obvious that it’s legal.

If you have legacy code like the code below, where foo.list() is a Java 1.4-compatible method returning java.util.List, you’ll normally see an “unchecked cast” warning on the assignment like so:

public void doSomeListStuff(Foo foo) {
    List list = foo.list(); // Warning: unchecked cast
    for (Blah blah : list) {

Normally, Eclipse offers to fix it for you like this:

public void doSomeListStuff(Foo foo) {
    List list = foo.list(); // Everything is A-OK!
    for (Blah blah : list) {

A better solution takes advantage of Java’s less-touted ability to annotate local variable declarations. By annotating the declaration and assignment instead of the method, the warning suppression is limited in scope to the assignment expression itself:

public void doSomeListStuff(Foo foo) {
    List list = foo.list();

    for (Blah blah : list) {

This keeps your code under maximum protection of Java’s generic strong typing. By annotating a whole method with @SuppressWarnings(“unchecked”), you may inadvertently introduce a later, unsafe cast that could cause a bug down the line.

Read full post

UPDATE: It’s live! The open-source project is up on Google Code and I’ve blogged a more about it.

I’m getting closer to having the GWT bindings that we wrote for Firefox ready for public release. What we’ve got is more than enough to write a complex extension. The bindings were even enough to write a prototype of an OOPHM server, itself written in GWT!

For now, just a taste of what extension development is like GWT, complete with strong typing, syntax checks, auto-completion and hosted mode support:

protected nsIFile createTempFile() {
    nsIFile file = nsIProperties.getService(";1")
        .get("TmpD", nsIFile.iid());
    if (!file.exists()) {
        file.create(nsIFile.DIRECTORY_TYPE, 0777);

    file.createUnique(nsIFile.NORMAL_FILE_TYPE, 0666);

    return file;

protected void write(String value, nsIFile file) {
    nsIFileOutputStream foStream = nsIFileOutputStream.createInstance(";1");
    foStream.init(file, 0x02 | 0x08 | 0x10, 0666, 0);
    foStream.write(value, value.length());

The bindings are all generated from the xulrunner SDK’s IDL files and include documentation, parameter names and constants:

     * @param file          - file to write to (must QI to nsILocalFile)
     * @param ioFlags       - file open flags listed in prio.h
     * @param perm          - file mode bits listed in prio.h
     * @param behaviorFlags flags specifying various behaviors of the class
     *        (currently none supported)
  public final native void init(nsIFile file, int ioFlags, int perm, int behaviorFlags) /*-{
    return this.init(file, ioFlags, perm, behaviorFlags);
Read full post

After receiving my Google Voice invite tonight and picking a phone number, seemingly at random, I discovered that I had picked a number with the same last four digits as one of my friends’ numbers.  If you are familiar with the Birthday Paradox, you might recognize the form of the problem.

So, what are the chances that given a number of friends, n, you don’t pick a number that ends in the last four digits as the number of another friend? Well, if it’s just you, the probability that you pick a number that noone else has is 1. With a single friend, the chances that you pick a safe number are 9999/10000. With two friends, the chances are (9998/10000) * (9999/10000), modeling it as on trial after another.

It turns out that you can expand this sequence out and wrap it up in a nice factorial equation. I won’t bore you with the details- it’s idential to the technique used on the wikipedia entry. You’ll end up with the following equation:

While having the equation on hand is nice, computing BigInt-magnitude factorials is outside Google’s math evaluation query and Apple’s Calculator application. Fortunately, Wolfram Alpha comes to the rescue (the first time I’ve been able to use it for a real question!):

Enter “10000! / (10000^n * (10000 - n)!)” and you’ll get a detailed analysis of the equation, along with a pretty graph:

After some research, I figured out how to limit the plot to get a better idea by using the “from” keyword: 10000! / (10000^n * (10000 - n)!) from n=0 to 300:

So, as you can see, if you’ve got 120 friends, your chances are pretty much 50/50 that you’ll have the same last four digits as one of them.

Read full post

Every developer has a different opinion of stored procedures. If you’ve worked on a few projects that involve databases, you’ll inevitably come across the as part of a project.

I’ve personally had a love/hate relationship with them. They require maintenance scripts like your regular table structure, but they aren’t structure. Generally, databases don’t give you good introspection ability for stored procedures either - fire-and-forget management.

Classically, stored procedures have been a bastardized version of the database’s native SQL. Take the basic SQL, add in some cursors, looping constructs and function invocation - that’s your stored procedure language. Depending on your database vendor, be prepared to deal with different syntaxes, punctuation and functionality.

No matter what, you’ll be writing your application in a different language, making the number of languages involved in any project with stored procs N + 1. If you choose to evaluate a different database vendor for a different project, or version 2.0 of your current project, your previous stored procedure may or may not translate.

Over the last decade and a bit, database vendors have been adding native language bindings to the database itself, allowing developers to write code in languages they are comfortable in, regardless of the database storage technology behind the scenes.

I’ll step back for a bit here - the role of application storage has been changing recently, pushed by a number of factors:

  1. Data-binding frameworks, like Hibernate, SQLAlchemy, Ruby on Rails and a number of others have been creating an abstraction layer over different database brands, as well as managing the flow of data between the live objects in the system.
  2. SQL-free large stores like Google’s BigTable, CouchDB and others have been pushing complexity out of the datastore and into the application itself.
  3. Languages with dynamic typing are in-vogue. Python, Ruby and PHP are popular, Java will be getting dynamic dispatch soon.
  4. New accessible structured storage formats, like Apache Thrift and Google’s Protobuf are allowing developers to create highly versionable “blobs” that are easy to write to, but hard to index and query.

Databases are going to have to evolve over the near future to suit the way that applications and hardware are developing today. Memory is cheap, disks are huge and time-to-market is one of the primary driving forces for developers.

I believe that the ideal role for a database is to be a high-powered host for serialization framework stubs. Instead of having to map application objects from database tables using clumsy SQL generation techniques and reconstructing objects from deep JOINs, the serialization frameworks should be injecting small stubs next to the database process itself. These stubs can coordinate data retrieval with the database itself - managing, grooming and traversing indexes, altering storage as needed for client-side data and sending appropriately structured data to the application.

Drizzle is a large step in the right direction. Instead of providing the smörgåsbord of features like the other DB vendors on the market, it provides a light-weight, modular architecture that allows you to swap and re-plug components like you would your application itself.

Here’s my plea to database developers: Let me compose my database server like I do my Java code, from appropriately tailored components optimized for my use. Let me run my Java/Python/Ruby code on the database server, right next to the data itself, in a language that I’m familiar and comfortable with - running on both sides of the database connection TCP connection.

Read full post

If you’re not familiar with video4all, let me start off with a quick intro: It allows you to use the standards-compliant HTML5 <video> tag on any browser, freeing you from the complexity of configuring markup for multiple video formats.

I’ve been tweaking the video4all source a bit since last night’s late release to fix some issues with other browsers and clean up some of the code. Adding support for browsers without binding languages was pretty simple - a setInterval runs and checks for new video elements every few seconds, converting them to flash embeds as needed. It’s not ideal (DOM mutation events would be great here), but it does a decent enough job.

One problem that I’ve run up against is that Safari 4 under windows will actually eat your <video> element’s tags if QuickTime isn’t installed!  They are no longer available in the document once eaten by the parser. In fact, there’s no way that I can find to recover these elements.  I’ve been trying to report a bug to Apple, but their bugreporter fails with a mysterious error every time I try to log in with my ADC credentials. I might consider adding a hack property to the video element to support this ultra-minority browser (-x-safari-win-mp4-src?), but I’ll keep researching ways to rescue the missing tags first.

So, what’s next for video4all? First of all, I’d like to remove the hard-coded FlowPlayer control bar that the player uses. It affects the aspect ratio of the video, making it difficult to size these things properly. Secondly, I’d like to start work on binding the rich video JS interface to the flash control behind the scenes. Even making the simple methods to start and stop the video available would be a big help!

(unfortunately this demo is no longer available, sorry!)

If you are interested in helping make this project better, visit us at the video4all project site and join the discussion. I’d love to hear some feedback about potential methods to fix Safari 4’s broken parser, even if they are glorious hacks!

Read full post