spacepup90
spacepup90

Reputation: 7

Trying to understand self keyword and how to use it in function chains - LUA

I understand how to stack functions when creating a new table from the beginning like so :

Test:newNumber(5):add5():add5() --create a Number{} with Number.Num=5 then add to self.num

but im having trouble passing in previously existing tables as so:

function EnemyBase:isStandingOver( Object )
    local o = Object
    for k , v in pairs(Creature_Bases) do 
        if (o.x and o.y are over v.x and v.y) then 
            setmetatable( Creature_Bases[k] , self ) 
            self.__index = self
            return Creature_Bases[k]
        end
    end
end

function EnemyBase:changeSprite()
    self.Sprite = self.SpriteTest
end 

function ManageEnemies()
    for k,v in pairs(Enemies) do 
        if EnemyBase:isStandingOver( Enemies[k] ) ~= nil then 
            EnemyBase:isStandingOver( Enemies[k] ):changeSprite()
        end 
    end 
end 

I know ill need to create a meta method table with the __index pointing to self at some point but i don't know when.

Upvotes: 0

Views: 1241

Answers (1)

Piglet
Piglet

Reputation: 28950

Let's first understand what self is.

function a:b() end is syntactic sugar for function a.b(self) end

A function defined like that has a parameter self.

Function call a:b() is syntactic sugar for a.b(a)

A function called like that always has a as its first argument which inside the function ends up as parameter self.

So if you have defined a function like that, you have a very simple way to access table a through self from within that function without explicitly using reference a. This comes in handy if you want to do OOP in Lua.

Then we have to understand what the __index metamethod is.

__index: The indexing access operation table[key]. This event happens when table is not a table or when key is not present in table. The metavalue is looked up in the metatable of table.

The metavalue for this event can be either a function, a table, or any value with an __index metavalue. If it is a function, it is called with table and key as arguments, and the result of the call (adjusted to one value) is the result of the operation. Otherwise, the final result is the result of indexing this metavalue with key. This indexing is regular, not raw, and therefore can trigger another __index metavalue.

Let's use both of it in a simple constructor:

MyClass = {}
function MyClass:New(name)
  local instance = setmetatable({}, self)
  self.__index = self
  instance.name = name
  return instance
end

function MyClass:SayName()
  print("my name is " .. self.name)
end

If we now do this:

local myFirstInstance = MyClass:New("John")
local mySecondInstance = MyClass:New("Bob")

myFirstInstance:SayName()
mySecondInstance:SayName()

what's going to happen?

We know MyClass:New() is equivalent to MyClass.New(MyClass). So in our contructor self refers to MyClass.

local instance = setmetatable({}, self) creates a new table and sets self which is MyClass as its metatable.

self.__index = self set's MyClass as the __index metavalue of itself.

The name is stored in each instance and the instance is returned.

Now if you call myFirstInstance:SayName(), Lua will look up myFirstIntance["SayName"]. It won't find anything. So it will check wether table myFirstInstance has a metatable and if so, if there is a __index metavalue. There is. getmetatable(myFirstInstance).__index is MyClass so it will now actually call MyClass.SayName(myFirstInstance). So in the end, both instances will print their own name even though they do not even implement a SayName function. And MyClass.SayName prints both instances names without knowing even knowing the instances or even their names.

Upvotes: 2

Related Questions