Struct Embedding in Lua

Lua supports tables, which can be used to create structures similar to structs in other languages. While Lua doesn’t have built-in support for object-oriented programming, we can use tables and metatables to achieve similar functionality.

-- Define a base table (similar to a struct)
local base = {}
base.__index = base

function base.new(num)
    local self = setmetatable({}, base)
    self.num = num
    return self
end

function base:describe()
    return string.format("base with num=%d", self.num)
end

-- Define a container table that "embeds" base
local container = {}
container.__index = container

function container.new(num, str)
    local self = setmetatable({}, container)
    self.base = base.new(num)
    self.str = str
    return self
end

-- "Inherit" methods from base
setmetatable(container, {__index = base})

-- Main function
local function main()
    -- Create a new container instance
    local co = container.new(1, "some name")

    -- Access fields
    print(string.format("co={num: %d, str: %s}", co.base.num, co.str))

    -- Access the base's num field directly
    print("also num:", co.base.num)

    -- Call the describe method
    print("describe:", co:describe())

    -- In Lua, we don't need to explicitly define interfaces.
    -- Any table with a 'describe' method can be treated as a "describer".
    local function printDescriber(d)
        print("describer:", d:describe())
    end

    -- Pass the container as a "describer"
    printDescriber(co)
end

-- Run the main function
main()

To run this Lua script, save it as struct_embedding.lua and execute it with the Lua interpreter:

$ lua struct_embedding.lua
co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

In this Lua implementation, we’ve simulated struct embedding using tables and metatables. The base table acts as our base “struct”, and the container table “embeds” it by storing an instance of base as one of its fields.

We use Lua’s metatables to implement method inheritance, allowing container to access methods from base. This is similar to how embedding works in other languages, where the embedding struct can call methods of the embedded struct.

Lua doesn’t have a built-in concept of interfaces, but we can achieve similar functionality by simply expecting objects to have certain methods. In this example, any table with a describe method can be passed to the printDescriber function, mimicking the behavior of interfaces in statically-typed languages.

This example demonstrates how Lua’s flexible nature allows us to implement concepts from other languages, even when they’re not built into the language itself.