Interfaces in Lua

In Lua, interfaces are not a built-in language feature. However, we can simulate similar behavior using tables and metatables. Here’s how we can implement the concept of geometric shapes:

local math = require("math")

-- We'll use a table to represent our "interface"
local geometry = {}

-- Rectangle implementation
local rect = {}
rect.__index = rect

function rect.new(width, height)
    return setmetatable({width = width, height = height}, rect)
end

function rect:area()
    return self.width * self.height
end

function rect:perim()
    return 2 * self.width + 2 * self.height
end

-- Circle implementation
local circle = {}
circle.__index = circle

function circle.new(radius)
    return setmetatable({radius = radius}, circle)
end

function circle:area()
    return math.pi * self.radius * self.radius
end

function circle:perim()
    return 2 * math.pi * self.radius
end

-- A generic function to measure any "geometry" object
local function measure(g)
    print(g)
    print(g:area())
    print(g:perim())
end

-- Main function
local function main()
    local r = rect.new(3, 4)
    local c = circle.new(5)

    -- We can use instances of rect and circle as arguments to measure
    measure(r)
    measure(c)
end

main()

In this Lua implementation:

  1. We define rect and circle as tables with their own methods, simulating classes.

  2. The new function for each shape acts as a constructor, using setmetatable to set up the metatable for method lookup.

  3. We implement area and perim methods for both shapes.

  4. The measure function takes any object that has area and perim methods, simulating an interface.

  5. In the main function, we create instances of rect and circle and pass them to measure.

To run this program, save it as geometry.lua and use:

$ lua geometry.lua
table: 0x55f748519990
12
14
table: 0x55f748519a00
78.539816339745
31.415926535898

This example demonstrates how we can achieve interface-like behavior in Lua using tables and metatables. While it’s not as strict as interfaces in statically-typed languages, it provides a flexible way to work with different types that share common behavior.