Object composition is a design pattern, not syntactic sugar. Implementing a basic pattern of object composition in Lua is as trivial as it is powerful. It’s one of my preferred methods of applying general interfaces to stateful objects.

local function CreateObject(obj)
    obj.Clone = function(self,target)
        for k,v in pairs(self) do
            target[k] = v
        end
        return target
    end
    return obj
end
local function CreatePositionableObject(obj)
    obj = CreateObject(obj)
    local attrs = {"Position","Orientation"}
    for _,a in pairs(attrs) do
        obj["Set"..a] = function (self,x)
            self[string.lower(a)] = x
        end 
        obj["Get"..a] = function (self,x)
            return self[string.lower(a)]
        end 
    end
    obj.MoveTo = function(self,x,y,z)
        print("Moving",self:GetName(),"to",x,y,z)
        self:SetPosition({x,y,z})
    end
    return obj
end
local function CreatePlayer(obj)
    obj = CreatePositionableObject(obj)
    local attrs = {"Name","HitPoints","ID","Class","Team"}
    for _,a in pairs(attrs) do
        obj["Set"..a] = function (self,x)
            self[string.lower(a)] = x
        end 
        obj["Get"..a] = function (self,x)
            return self[string.lower(a)]
        end 
    end
    obj.FireAt = function(self,target)
        print(self:GetName(),"firing at",target:GetName())
    end
    return obj
end
local function CreateFakePlayer(obj)
    obj = CreatePlayer(obj)
    obj.MoveTo = function(self,x,y,z)
        print("Fake players can't actually move...")
    end
    obj.FireAt = function(self,target)
        print(self:GetName(),"can't shoot at",target:GetName())
    end
    return obj
end

local p1 = CreatePlayer({})
local p2 = CreateFakePlayer({})

p1:SetName("Player 1")
p2:SetName("Player 2")
p1:MoveTo(1,2,3)
p2:MoveTo(3,2,1)
p1:FireAt(p2)
p2:FireAt(p1)
print(p1:GetName() .. "'s position",p1:GetPosition()[1],p1:GetPosition()[2],p1:GetPosition()[3])
local p3 = p1:Clone({})
p3:SetName("Player 3")
p3:FireAt(p1)

This works for the simple reason that tables in Lua are object references, so changing them inside of a function has side effects. Because of this, it is always a good idea to only change tables being used as object via Getter/Setter functions so that it is easier to debug.

The above code creates a Player and a FakePlayer, the equivalent inheritance path would be Object > PositionableObject > Player > FakePlayer.

Note that self is a convention, not a keyword!