Default Values for Tables

Problem Definition Assume that it is necessary to have default values on a set of tables

    • If the table does not have a value for a key then
        • A default value is to be given. Note that in this case
        • only one default per table is allowed

Problem Solution Discussion

1\. Each read of a value for a key from the table will 
   return a value or if the key does not exist in the table a nil.
2\. A call to return an absent key can be intercepted by defining 
   the __index metamethod.
3\. The __index metamethod can then return a default value
4\. The question becomes how to make the metatable efficient
```

_**Solution 1**_

```

--[[This is a function which will set a default for a table.
    Note that a new metatable is created for each table.  The function
    creates only one default per table.  Each use of this function creates 
    a closure this can be expensive in terms of memory used (metatable and default) 
    if there are many tables]]
function setDefault(table, default)
local metatable = {__index = function () return default end} -- a new closure, when __index is called, default is known
setmetatable(table, metatable)
end

theTable = {x=10, y=20}
print(theTable.x, theTable.z)

setDefault(theTable, -1)
print (theTable.x, theTable.z)

setDefault(theTable, 0)
print (theTable.x, theTable.z)
```

_**Solution 2**_

```

--[[Here we set default values for indices that are used that have no table entries
    by only using one metatable, saves memory.  The function saves the default
    data in the table itself.  It uses an oddly named variable, three underscores (___)
    as the variable name]]
local metatable = {__index = function(t) return t.___ end}
function setDefault(table, default)
table.___ = default
setmetatable(table, metatable)
end

theTable = {x=10, y=20}
print(theTable.x, theTable.z)

setDefault(theTable, -1)
print (theTable.x, theTable.z)

```

_**Solution 3**_

```

--[[set default values for indices that are used that have no table entries
    by only using one metatable, saves memory.  The function here saves the default
    data in the table itself.  In this case it uses the name "key" as the variable name

    Note: to create key it is set up as a table and created using a local variable.  Its
    value is then initialize with the default (which can be of any type) within the
    setDefault function.  This is somewhat obscure and subtle, we end up with an
    index and value pair where the index is an empty table (called key) and the value 
    is the default]]
local key = {}
local metatable = {__index = function(t) return t[key] end}
function setDefault(table, default)
table[key] = default
setmetatable(table, metatable)
end

theTable = {x=10, y=20}
print(theTable.x, theTable.z)

setDefault(theTable, -1)
print (theTable.x, theTable.z)
```