
- Lua Tutorial
- Lua - Home
- Lua Basics
- Lua - Overview
- Lua - Environment
- Lua - Basic Syntax
- Lua - Comments
- Lua - Print Hello World
- Lua - Variables
- Lua - Data Types
- Lua - Operators
- Lua - Loops
- Lua - Generic For
- Lua - Decision Making
- Lua - Date and Time
- Lua Functions
- Lua - Functions
- Lua - Multiple Results
- Lua - Named Arguments
- Lua - Default/Optional Arguments
- Lua - Closures
- Lua - Uses of Closures
- Lua - Local Functions
- Lua - Anonymous Functions
- Lua - Functions in Table
- Lua - Proper Tail Calls
- Lua Strings
- Lua - Strings
- Lua - String Concatenation
- Lua - Loop Through String
- Lua - String to Int
- Lua - Split String
- Lua - Check String is NULL
- Lua Arrays
- Lua - Arrays
- Lua - Multi-dimensional Arrays
- Lua - Array Length
- Lua - Iterating Over Arrays
- Lua - Slicing Arrays
- Lua - Sorting Arrays
- Lua - Merging Arrays
- Lua - Sparse Arrays
- Lua - Searching Arrays
- Lua - Resizing Arrays
- Lua - Array to String Conversion
- Lua - Array as Stack
- Lua - Array as Queue
- Lua - Array with Metatables
- Lua - Immutable Arrays
- Lua - Shuffling Arrays
- Lua Iterators
- Lua - Iterators
- Lua - Stateless Iterators
- Lua - Stateful Iterators
- Lua - Built-in Iterators
- Lua - Custom Iterators
- Lua - Iterator Closures
- Lua - Infinite Iterators
- Lua - File Iterators
- Lua - Table Iterators
- Lua - Numeric Iterators
- Lua - Reverse Iterators
- Lua - Filter Iterators
- Lua - Range Iterators
- Lua - Chaining Iterators
- Lua Tables
- Lua - Tables
- Lua - Tables as Arrays
- Lua - Tables as Dictionaries
- Lua - Tables as Sets
- Lua - Table Length
- Lua - Table Iteration
- Lua - Table Constructors
- Lua - Loop through Table
- Lua - Merge Tables
- Lua - Nested Tables
- Lua - Accessing Table Fields
- Lua - Copy Table by Value
- Lua - Get Entries from Table
- Lua - Table Metatables
- Lua - Tables as Objects
- Lua - Table Inheritance
- Lua - Table Cloning
- Lua - Table Sorting
- Lua - Table Searching
- Lua - Table Serialization
- Lua - Weak Tables
- Lua - Table Memory Management
- Lua - Tables as Stacks
- Lua - Tables as Queues
- Lua - Sparse Tables
- Lua Lists
- Lua - Lists
- Lua - Inserting Elements into Lists
- Lua - Removing Elements from Lists
- Lua - Iterating Over Lists
- Lua - Reverse Iterating Over Lists
- Lua - Accessing List Elements
- Lua - Modifying List Elements
- Lua - List Length
- Lua - Concatenate Lists
- Lua - Slicing Lists
- Lua - Sorting Lists
- Lua - Reversing Lists
- Lua - Searching in Lists
- Lua - Shuffling List
- Lua - Multi-dimensional Lists
- Lua - Sparse Lists
- Lua - Lists as Stacks
- Lua - Lists as Queues
- Lua - Functional Operations on Lists
- Lua - Immutable Lists
- Lua - List Serialization
- Lua - Metatables with Lists
- Lua Modules
- Lua - Modules
- Lua - Returning Functions from Modules
- Lua - Returning Functions Table from Modules
- Lua - Module Scope
- Lua - SubModule
- Lua - Module Caching
- Lua - Custom Module Loaders
- Lua - Namespaces
- Lua - Singleton Modules
- Lua - Sharing State Between Modules
- Lua - Module Versioning
- Lua Metatables
- Lua - Metatables
- Lua - Chaining Metatables
- Lua Coroutines
- Lua - Coroutines
- Lua File Handling
- Lua - File I/O
- Lua - Opening Files
- Lua - Modes for File Access
- Lua - Reading Files
- Lua - Writing Files
- Lua - Closing Files
- Lua - Renaming Files
- Lua - Deleting Files
- Lua - File Buffers and Flushing
- Lua - Reading Files Line by Line
- Lua - Binary File Handling
- Lua - File Positioning
- Lua - Appending to Files
- Lua - Error Handling in File Operations
- Lua - Checking if File exists
- Lua - Checking if File is Readable
- Lua - Checking if File is Writable
- Lua - Checking if File is ReadOnly
- Lua - File Descriptors
- Lua - Creating Temporary Files
- Lua - Working with Large Files
- Lua Advanced
- Lua - Error Handling
- Lua - Debugging
- Lua - Garbage Collection
- Lua - Object Oriented
- Lua - Web Programming
- Lua - Database Access
- Lua - Game Programing
- Lua Useful Resources
- Lua - Quick Guide
- Lua - Useful Resources
- Lua - Discussion
Lua - Chaining Metatables
Chaining metatables is a very effective technique to implment inheritance like feature in Lua and to delegate operations to different tables or objects as per the requirement. Chaining is achieved with the use of __index() metamethod
Chaining metatables can be referred as a fallback mechanism for tables. When we try to access a non-existent key in a table, lua looks for its metatable for __index() method implementation. If __index() is another table, then Lua keeps it search in the next table and continues making a chain of metatables to be searched for __index() method implementation.
Working of __index as as a table
Consider an object or table as table1 with a missing key.
A metatable, metatable1 is set on the table as setmetatable(table1, metatable1)
metatable1 is having __index field pointing to another table as table2.
Now first Lua looks for the missing key in table2 because of __index field. If key is found, value from table2 is returned.
If key is not found and table2 is again having metatable2 with __index set to table3, Lua will continue search in table3 and so on.
Example - Chaining Metatable using __index as table
Let's create an inheritance chain of Animal → Dog &rarr Pug.
main.lua
-- Base class: Animal Animal = { sound = "Generic Roar" } Animal.__index = Animal -- method makeSound function Animal:makeSound() print(self.sound) end -- Subclass: Dog, inheriting from Animal Class Dog = setmetatable({ breed = "Bulldog" }, { __index = Animal }) Dog.__index = Dog -- method specific to Dog class function Dog:bark() print("Woof!") end -- override parent method function Dog:makeSound() print("Woof woof!") end -- Subclass: Pug, inheriting from Animal Class Pug = setmetatable({ name = "PUG" }, { __index = Dog }) -- for method calls when : syntax is used. Pug.__index = Pug -- method specific to Pug class function Pug:snore() print("Zzz..") end -- Create instance of Animal local animal = {} setmetatable(animal, { __index = Animal }) -- Create instance of Dog local dog = {} setmetatable(dog, { __index = Dog }) -- Create instance of Pug local pug = {} setmetatable(pug, { __index = Pug }) -- Chaining process animal:makeSound() -- Generic Roar dog:makeSound() -- Woof woof! (overridden) dog:bark() -- Woof! (inherited) print(dog.sound) -- Generic Roar (inherited) print(dog.breed) -- Bulldog (own property) pug:makeSound() -- Woof woof! (inherited from Dog) pug:bark() -- Woof! (inherited from Dog) pug:snore() -- Zzz.. (own method) print(pug.sound) -- Generic Roar (inherited from Animal) print(pug.breed) -- Bulldog (inherited from Dog) print(pug.name) -- PUG (own property)
Output
When we run the above program, we will get the following output−
Generic Roar Woof woof! Woof! Generic Roar Bulldog Woof woof! Woof! Zzz.. Generic Roar Bulldog PUG
Working of __index as as a function
We can use __index metamethod as a function as well. This function will return the table and now it will work in the same fashion as explained earlier,
main.lua
-- Table 1 Table1 = { value1 = "Hello" } -- Table 2 Table2 = { value2 = "World" } setmetatable(Table1, { __index = Table2 }) -- creating instance local instance = {} setmetatable(instance, { __index = function(table, key) print("Checking for missing key '" .. key .. "'") return Table1[key] end }) -- prints Checking for missing key 'value1' \n Hello print(instance.value1) -- prints Checking for missing key 'value2' \n World print(instance.value2) -- prints Checking for missing key value3 \n nil print(instance.value3)
Output
When we run the above program, we will get the following output−
Checking for missing key 'value1' Hello Checking for missing key 'value2' World Checking for missing key 'value3' nil
Advantages of Chaining Metatables
Inheritance − We can create hiearchies of subclasses inheriting properties from super classes.
Reusability − Common code can be defined in base class and then can be reused by sub classes.
Delegation − Certain operations can be delegated to a specialized object like logging.
Organization − Code can be structured by define tables, chaining them with specialized tables and so.