- 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 - Proxy Tables with Metatables
- Lua - Use Cases for Proxy Table
- Lua - Delegation and Tracing via Proxy Tables
- Lua - Metatables vs Metamethods
- Lua - Fallback Mechanisms in Metatables
- Lua - Fallback Cases for Indexing Metamethods
- Lua - Fallback Cases for Arithmetic and Comparison Metamethods
- Lua - Fallback Cases for Other Metamethods
- Lua - Customizing Behavior with Metatables
- Lua - Controlling Table Access
- Lua - Overloading Operators
- Lua - Customizing Comparisons
- Lua - Making a Table Callable
- Lua - Customizing String Representation
- Lua - Controlling Metatable Access
- Lua Coroutines
- Lua - Coroutines
- Lua - Coroutine Lifecycle
- Lua - Communication Between Coroutines
- Lua - Coroutines vs Threads
- Lua - Chaining Coroutines
- Lua - Chaining Coroutines With Scheduler
- Lua - Chaining Coroutines Using Queues
- Lua - Coroutine Control Flow
- Lua - Nested 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 - File Iterators
- 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
- Sorting Algorithms
- Lua - Bubble Sort
- Lua - Insertion Sort
- Lua - Selection Sort
- Lua - Merge Sort
- Lua - Quick Sort
- Searching Algorithms
- Lua - Linear Search
- Lua - Binary Search
- Lua - Jump Search
- Lua - Interpolation Search
- Regular Expression
- Lua - Pattern Matching
- Lua - string.find() method
- Lua - string.gmatch() method
- Lua - string.gsub() method
- Lua Useful Resources
- Lua - Quick Guide
- Lua - Useful Resources
- Lua - Discussion
Lua - Controlling Access to a Table
Lua metatable has two specific fields __index and __newindex to control table access. In this chapter, we're covering both the fields with metamethods with examples.
Using __index metamethod
__index metamethod is activated or invoked by Lua when we try to access a key in a table which is not present. We can use __index metamethod for −
Default Values − We can return a different default value instead of returning nil when a key is missing in the target table.
Delegation − We can forward the key lookup to other table.
Lazy Loading − We can load values when first accessed instead of load time to improve performance.
Virtual Property − We can compute values dynamically based on provided key instead of looking up stored data.
Example - Setting default values using __index
main.lua
-- Default values
local defaults = { width = 100, height = 50 }
-- main table
local shape = {}
-- metatable
local meta = { __index = defaults }
-- set metatable
setmetatable(shape, meta)
-- get default values of keys
-- prints 100
print(shape.width)
-- prints 50
print(shape.height)
-- prints nil, as not present in defaults
print(shape.color)
Output
When we run the above program, we will get the following output−
100 50 nil
Example - Delegation using __index
main.lua
-- main table
local shape = { width = 100, height = 50 }
-- proxy table
local proxy = {}
-- metatable to delegate to main table
local meta = { __index = shape }
-- set metatable to proxy
setmetatable(proxy, meta)
-- get value from main table via proxy
print(proxy.width)
-- set a value to proxy, but not to main table
proxy.color = "red"
-- try to get color from shape, prints nil
print(shape.color)
Output
When we run the above program, we will get the following output−
100 nil
Using __newindex metamethod
__newindex metamethod is activated or invoked by Lua when we try to assign a new key to the table. We can use __newindex metamethod for −
Read Only Table − We can make a table readonly by not allowing any new entry to it.
Validation − We can perform validation on the value assigned as required type of value or range of values.
Side Effects − We can perform actions as side effects while setting values like logging, tracing etc.
Delegation − We can even assign value to different table or object.
Example - Delegation using __newindex
main.lua
-- main table
local config = { max_users = 10 }
-- set metatable to make table readonly
-- no new entry is allowed
setmetatable(config, { __newindex = function(table, key, value)
error("No new entry allowed.", 2)
end })
-- this will throw an error
config.max_connections = 15
Output
When we run the above program, we will get the following output−
lua: main.lua:11: No new entry allowed.
stack traceback:
[C]: in function 'error'
main.lua:7: in metamethod 'newindex'
main.lua:11: in main chunk
[C]: in ?
Example - Validation using __newindex
main.lua
-- main table
local settings = {}
-- set a metatable to validate inputs to be numbers only
setmetatable(settings, { __newindex = function(table, key, value)
if type(value) == "number" then
rawset(table, key, value)
else
error("Value for " .. key .. " must be a number", 2)
end
end })
-- set a valid value
settings.volume = 75
print(settings.volume)
-- setting string throws an error
settings.base = "high"
Output
When we run the above program, we will get the following output−
75
lua: main.lua:16: Value for base must be a number
stack traceback:
[C]: in function 'error'
main.lua:9: in metamethod 'newindex'
main.lua:16: in main chunk
[C]: in ?