Autovivification

From Wikipedia, the free encyclopedia
Jump to: navigation, search

Autovivification is a distinguishing feature of the Perl programming language involving the dynamic creation of data structures. Autovivification is the automatic creation of a variable reference when an undefined value is dereferenced. In other words, Perl autovivification allows a programmer to refer to a structured variable, and arbitrary sub-elements of that structured variable, without expressly declaring the existence of the variable and its complete structure beforehand.

In contrast, other programming languages either: 1) require a programmer to expressly declare an entire variable structure before using or referring to any part of it; or 2) require a programmer to declare a part of a variable structure before referring to any part of it; or 3) create an assignment to a part of a variable before referring, assigning to or composing an expression that refers to any part of it.

Perl autovivication can be contrasted against languages such as Python, PHP, Ruby, and many of the C style languages. It can be compared to the HTML standard's "named access on the window object"[1] which results in corresponding globally scoped variables being automatically accessible to browser-based JavaScript.

Hashes[edit]

It is important to remember that autovivification happens when an undefined value is dereferenced. An assignment is not necessary. The debugger session below illustrates autovivification of a hash just from examining it:

  DB<1> x \%h
0  HASH(0x2f1a248)
     empty hash
  DB<2> x $h{1}{2}{3}{4}
0  undef
  DB<3> x \%h
0  HASH(0x2f1a248)
   1 => HASH(0x2f1a260)
      2 => HASH(0x29a3c68)
         3 => HASH(0x2dc3038)
              empty hash
  DB<4>

The debugger session below illustrates autovivification of a hash from assigning to an inner hash:

  DB<1> $h{A}{B}{C}{D}=1
  DB<2> x \%h                                                                  
   0  HASH(0x83c71ac)
   'A' => HASH(0x837d50c)
      'B' => HASH(0x83c71e8)
         'C' => HASH(0x83c7218)
            'D' => 1
  DB<3>

Hashes several layers deep were created automatically without any declarations. Autovivification can prevent excessive typing. If Perl did not support autovivification, the structure above would have to be created as follows:

  DB<1> %h = (A => {B => {C => {D => 1}}})
  DB<2> x \%h                                                                  
  0  HASH(0x83caba4)
   'A' => HASH(0x83cfc28)
      'B' => HASH(0x83cab74)
         'C' => HASH(0x83b6110)
            'D' => 1
  DB<3>

File and Directory Handles[edit]

Perl 5.6.1 and newer support autovivification of file and directory handles. Calling open() on an undefined variable will set it to a filehandle. According to perl561delta, "[t]his largely eliminates the need for typeglobs when opening filehandles that must be passed around, as in the following example:

    for my $file ( qw(this.conf that.conf) ) {
        my $fin = open_or_throw('<', $file);
        process_conf( $fin );
        # no close() needed
    }
    use Carp;
    sub open_or_throw {
        my ($mode, $filename) = @_;
        open my $h, $mode, $filename
            or croak "Could not open '$filename': $!";
        return $h;
    }

Python[edit]

Python's collections module contains a defaultdict class[2] which can be used to implement autovivificious dictionaries via a relatively simple recursive function.[3]

from collections import defaultdict
 
Tree = lambda: defaultdict(Tree)
 
t = Tree()
 
t[1][2][3] = 4
t[1][3][3] = 5
t[1][2]['test'] = 6
 
def autovivify(levels=1, final=dict):
    '''Returns a nested defaultdict with a set number of levels and defined final structure.
    '''
    return (defaultdict(final) if levels < 2 else
            defaultdict(lambda: autovivify(levels - 1, final)))
 
words = autovivify(5, int)
words["sam"][2012][5][25]["hello"] += 1
words["sue"][2012][5][24]["today"] += 1
 
def convert_nested_dd(dd):
    '''Converts a nested defaultdict back into a native dictionary.
    '''
    return {k:convert_nested_dd(v) for k,v in dd.items()} if isinstance(dd, defaultdict) else dd

Ruby[edit]

Ruby hashes can take a block specifying an object to be returned for non-existing indexes. These can be used to implement autovivificious maps.

tree = proc { Hash.new { |hash, key| hash[key] = tree.call } }
 
lupin = tree.call
lupin["express"][3] = "stand and deliver"

PHP[edit]

PHP arrays are natively autovivificious.

$arr = array();
$arr["express"][3] = "stand and deliver";

However, this only applies to assignment, and not array access.

See also[edit]

References[edit]

  1. ^ http://www.whatwg.org/specs/web-apps/current-work/#named-access-on-the-window-object
  2. ^ "collections - High-performance container datatypes - Python v2 documentation". Retrieved 2013-08-14. 
  3. ^ "What is the best way to implement nested dictionaries in Python?". Retrieved 2013-08-14. 

External links[edit]