Auto-Vivifaction in JavaScript

What? You mean auto-verification? NO!

Vivification is when we directly assign a deeply nested attribute/property while the ones above don’t exist, and yet the entire hierarch is automatically created.

Take example of *nix mkdir command. It creates a new directories in a given directory

# Create a single directory in current directory
$ mkdir temp
$ tree
.
└── temp

But, we can also create sub-sub-sub directory

# Try to create a nested directory
# When outer ones don't exist
$ mkdir faltu/bakwaas/bekaar

mkdir: faltu/bakwaas: No such file or directory

See, no vivification! We are unable to create bekaar directory because faltu and bakwaas don’t exist.
We will be forced to create parent directories before the child and grandchild.

# Sigh! One at at ime
$ mkdir faltu
$ mkdir faltu/bakwaas
$ mkdir faltu/bakwaas/bekaar
$  tree
.
└── faltu
    └── bakwaas
        └── bekaar

Don’t we wish we could directly create bekaar without creating faltu and bakwaas first?
Welcome to Auto-vivification. Automatic creation of outer structure when directly creating a nested structure.

# Vivification in mkdir (watch the p)
$ mkdir -p good/bad/ugly
$ tree
.
└── good
    └── bad
        └── ugly

So now we understand auto-vivification, can we do this in programming languages as well?
Well, *some* of them, like perl

perl lnaguage has support auto-vivification. We can directly assign to $year and it would automatically create the chain of $college and $stream

my $univ;
my $college="SITS";
my $stream="BECS";
my $year=4;

$univ{$college}{$stream}{$year}="A+";
print($univ{$college}{$stream}{$year});

Let's do it in JavaScript
// No auto-vivification in JavaScript

// Create top level object
let univ = {};

// Now assign to a deeper level
univ.college.stream.year = "A+"; // ERROR

--------------------------------------------
Output
--------------------------------------------
univ.college.stream.year = "A+"; // ERROR
             ^

TypeError: Cannot read property 'stream' of undefined

Yep, that’s right. While we have an object called univ, currently we do not have a property called ‘college’ and ‘stream’ while trying to assign value to ‘year’

Let’s understand the problem first. When we try to assign to a nested property in JavaScript, it tries to “get” the parent property, which does not exist and we get an error.

How about if we intercept that and create the parent property on-the-fly? Hmm…

let univ = {
  // If property exists return it
  // Otherwise, create it and return it
  get: (prop) => { 
    this[prop] 
      ? this[prop] 
      : this[prop] = {} }
}

univ.college = "SITS"; // WORKS!!!
console.log(univ);

univ.college.stream.year = "BECS"; // ERROR
console.log(univ); 

Well, our joy was short-lived. While it can create any property on the fly inside univ
univ.college = "ABCD";
univ.establised = 1884;
univ.name = "Amazing";

but we cannot do it at the next level, so this doesn’t work
univ.college.stream = "CS";

JavaScript Proxy object to the rescue!
A Proxy object plugs-in another object and can be handler for certain functions/properties.
E.g. We can have a Proxy object which handles get for the handled object.

// Use Proxy object and handler to create a new property on the fly
let AutoViv = () =>

  // Proxy() object of JavaScript
  new Proxy({}, // ANY blank object
    {
      // if property exists, return it
      // Otherwise, create it
      get: (obj, prop) => 
        prop in obj 
          ? obj[prop] 
          : obj[prop] = AutoViv()
    }
  )
Time to put this to test!
// Use Proxy object and handler to create a new property on the fly
let AutoViv = () =>

  // Proxy() object of JavaScript
  new Proxy({},
    {
      // Handler checks if prop does not exists, creates it
      get: (obj, prop) => 
        prop in obj 
          ? obj[prop] 
          : obj[prop] = AutoViv()
    }
  )

// Create only TOP level
let univ = AutoViv();

// Now assign to deeper level
univ.college.stream.year = "A+";
console.log("univ", univ);

let univ2 = AutoViv();
univ2['college']['stream']['year'] = "A+";

// Bingo! It works
console.log("univ2", univ2);

Output
univ { college: { stream: { year: 'A+' } } }
univ2 { college: { stream: { year: 'A+' } } }

Congratulations! We have an Auto-Vivification object in JavaScript now, which allows us to create a nested property without first defining its parent property!

Can we do it in other languages too? Maybe next post.. AutoVivification in Python

Auto vivification Series

  1. Auto vivification in JavaScript
  2. Auto vivification in Python
  3. Auto vivification in JavaScript (Upgraded)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s