June 07, 2007

Collections + Generics => autovivification?

One of the many nice things about Perl is autovivification -- you don't need to assume a hash key exists before you can assign to it, as many times as you like. So you can do something like:

my %employees = ();
$employees{'Steve McQueen'}->{salary} = 50000;

And the intermediate hash attached to the key 'Steve McQueen' will be created along the way for you. Now, like a lot of things in Perl this can lead to silent failures -- if I now do this:

my %employees = ();
$employees{'Steve Mcqueen'}->{department} = 'Kicking ass';
                   ^^^

...a whole new hash would be created and the data won't be where I expect. But there are many ways to get around this, most of which you should be doing anyway (case-insensitive keys, IDs as keys, tests, etc.). Perl will let you shoot yourself in the foot.

The equivalent in Java would be:

Map<String,EmployeeData> employees = new HashMap<String,EmployeeData>();
employees.get( "Steve McQueen" ).setSalary( 50000 );

Instead, I need to do:

if ( ! employees.containsKey( "Steve McQueen" ) ) {
   employees.put( "Steve McQueen", new EmployeeData() );
}
employees.get( "Steve McQueen" ).setSalary( 50000 );

Or even more egregious, because all we're asking the language to do is pick a reasonable default implementation of an interface:

Map<Integer,List<Work>> workByID = new HashMap<String,List<Work>>();
Work work = getWorkFromSomewhere();

// one line workByID.get( 15 ).add( work );

// ...vs four lines if ( ! workByID.containsKey( 15 ) ) { workByID.put( 15, new ArrayList() ); } workByID.get( 15 ).add( work ); </pre>

I know some frameworks do this -- in particular, object creation frameworks that map data coming in (over HTTP, via an XML/JSON graph, etc.) to objects. But should you really need a framework for this, each with its own quirks? (Yes, OGNL, or at least OGNL + Webwork, is quirky.) Shouldn't the language and data structure be smart enough to figure that it can pick a reasonable List implementation for you if there's none specified by use? Or that it can use the no-arg constructor for random JavaBeans?

It winds up encouraging the use of lots of little classes. By itself that's not such a bad thing, I'm a fan of using lots of little classes. But not when most of them do no more than add null checks to the standard library's data structures.

Next: Missing 'load' from Java 6 JavaScript?
Previous: Another sign of getting old