The lowdown on autovivification

Autovivification is an unusual feature of the Perl programming language having to do with the dynamic creation of data structures. The essence of AV is this: Trying to access an element of a hash (associative array) or array that does not already exist creates both the hash or array, and all elements below the given index for the array.

This is in contrast to most other high level languages, in which you must explicitly create a given hash or array before you use it. This includes Python, PHP, JavaScript and all the C style languages. (I am referring only loosely to hashes in the given languages.)

I have given, below, a Perl program demonstrating several examples of autovivification. I'm not certain example 1 is considered autovivification by Perl buffs, or just Perl array behaviour. (Edit: Yes, it is. Thanks, Simpleton.) See the main reference at the bottom for a more drawn out explanation and examples set.

Thoughts on autovivification

As a C kind of person, autovivification did not at first make a great deal of sense to me. It took me awhile to understand all of the examples in the article and successfully write my own. It does make sense, though; albeit probably much more so to someone with Perl experience.

My opinion, predictably, is thus: Autovivification is not a Bad Thing or even Good and Wrong; it is a high-level feature that can be used or abused. It can serve an experienced programmer well in accomplishing what would otherwise be a difficult (or lengthy) task. (Operations on trees come to mind.) Just the same, it can be used by a newbie or 1337 |-|@xx0r to write terrible code that cannot be modified or understood. Therefore, it should be understood by knowledgeable Perl coders, and used with discretion.

I am tempted to give a tutorial on how to use autovivification, but reading through the example program should suffice for anyone who really needs to understand the issue.

Code listing: autoviv.pl

I am not a Perl monger; in fact, most of what I know about Perl I (re)learned over the course of the morning on which I wrote this. Sorry.


#!/usr/bin/perl

print "Autovivification examples by quamaretto\n";

print "\nPart 1: Normal procedures; no AV \n";
print "Regular variable use:\n";
$a = 5;
print "Set a to 5...\n";
print "value of a: $a\n";

print "Regular array use:\n";
print "\nSetting elements of fib to 1,1,2,3,5...\n";
@fib = (1,1,2,3,5);
print "Value of 3rd element in e: " . $e[2] . "\n"; 

print "Regular hash use:\n";
print "\nSetting up some keys and values in 'numbers'...\n";
%numbers = (1,'one',2,'two',3,'MONKEYS');
%numbers->{111} = 'eleventy-one';
print "Value from key 111 in numbers: " . %numbers->{111} . "\n";

print "\nExamples of autovivification:\n";

print "\nExample 1: Ghost elements in arrays\n";
print "Setting elements of fib to 1,1,2,3,5...\n";
@fib = (1,1,2,3,5);
$size = @fib;
print "Atoms in fib: $size\n"; 
print "Setting eighth element of fib...\n";
@fib->[7] = 21;
$size = @fib;
print "Atoms in fib: $size\n"; 
print "By inference, the sixth and seventh elements of fib have been auto-vivified.\n";
print "\nNon-example 1: Reading an array element does not create it\n";
print "Attempting to get 11th elements of fib: " . @fib->10 . "\n";
$size = @fib;
print "Atoms in fib: $size\n"; 
print "No autovivification here.\n";
print "\nExample 2: Nested reading causes autovivification\n";
print "Printing non existant 3rd nested element of ";
print "twelvth nested element of fib: " . @fib->[11]->[2] . "\n";
$size = @fib;
print "Atoms in fib: $size\n"; 
@11 = @{@fib->[11]}; # Is this line wrong? Someone?
$size = @11;
print "Atoms in fib[11]: $size\n"; 
print "Perl auto-vivifies fib[11], with no elements.\n" ;

print "\nExample 3: Nesting a hash automagically\n";
print "Setting up hobbit first name/last names in 'hobbits'\n";
%hobbits = ('Bilbo','Baggins','Frodo','Baggins','Samwise','Gamgee');
$size = keys(%hobbits);
print "Keys in hobbits: $size\n";
print "Nesting hash within value of key 'meri' without declaring it.\n";
%hobbits->{'Meri'}->{'adoc'} = 'Brandybuck';
$size = keys(%hobbits);
print "Keys in hobbits: $size\n";
%meri = %hobbits->{'Meri'};
$size = keys(%meri);
print "Nubmer of keys in Meri in hobbits: $size\n";
print "The hash in the key 'meri' within the hash is auto-vivified.\n";

print "\nExample 4: Ridiculous, arbitrary deep nesting\n";
print "Setting a value at the end of a long string of b.s....\n";
%a = {};
%a->{'b'}[3]{'pie'}[0]{'lesbian monkeys'} = 'soy';
print "Deeply nested value: " . %a->{'b'}->[3]->{'pie'}->[0]->{'lesbian monkeys'} . "\n";
print "Here, we create a hash within a 1 element array within a hash within ";
print "a four element array with the hash 'a'. Everything beyond 'a'";
print " has been auto-vivified as the correct type.\n";
Notes:

Forgive a Perl newbie for noding this; apparently, no one else wanted to do it. (I can understand why. It took me all morning.) Also, this was in fact, a nodeshell challenge of sorts from some time back.

References:

  • http://www.perlguy.com/articles/autoviv.html - A good summary of AV
  • http://www.dwam.net/docs/perl/lib/Pod/perlref.html - A very long-winded discussion of Perl references
  • http://www.perl.org - Perl home

Log in or register to write something here or to contact authors.