Collections + Generics = autovivification?

lachoy on 2007-06-07T21:19:22

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 );

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.

Posted from cwinters.com; read original


Vocabulary

stu42j on 2007-06-08T14:04:28

One of the many nice things about Perl is you get to learn cool words like: autovivification.

new() constaint in C#

gav on 2007-06-10T00:47:54

I'm not sure about Java, but C# has a nifty feature where you can add a constraint that the type used must support a public parameterless constructor.

class AutoVivifyDictionary<TKey, TValue> : Dictionary<TKey, TValue> where TValue : new() {

    public new TValue this[TKey key] {
        get {
            TValue v;
            if (this.TryGetValue(key, out v)) {
                return v;
            } else {
                this.Add(key, (v = new TValue()));
                return v;
            }
        }
        set {
            base[key] = value;
        }
    }

}
I quite like generics but it does seem to involve a lot of headache inducing angle brackets.