0

I'd like to accomplish one thing with metatablitz, but i don't understand how to do it right. More precisely, i implemented it, but i miss one little thing - so that in the right place i can use a colon.

The code below is simple and speaks for itself. How do i make sure that Z:Entity.Create() does not cause an error?

Z = {
  Entity = {
    Create = function(name)
      print ('Entity name:', name)
    end,
  }
}

setmetatable(Z.Entity, {__call = function(self, ...)
  print (...)
end})

local p1 = Z:Entity('New entity')  -- table: 0xb8f730 New entity
p1 = Z.Entity.Create('test')  -- Entity name: test
p1 = Z:Entity.Create('test')  -- lua: [string "<eval>"]:16: function arguments expected near '.'   

Any advice or help would be welcome!

Aquinary
  • 71
  • 5
  • What is `Z:Entity.Create('test')` supposed to do? You can fix the error by using a dot instead of a colon, like in the statement before it. – luther Sep 26 '21 at 22:27

2 Answers2

1

a:name() is syntactic sugar for a.name(a)

So if you write Z:Entity.Create('test'), the interpreter expects Entity to be a function value. But instead of the expected function arguments in parenthesis there is a dot.

Your code doesn't make too much sense though. Why do you assign three different things to p1?

Piglet
  • 27,501
  • 3
  • 20
  • 43
1

Your code isn't really self explanatory, you need to explain what you are trying to do and why you want to use a colon. I recommend reading up on the syntax, maybe with this question. The colon basically is a shortcut for calling a function on an object and passing the object as the first parameter. When defining a function using the colon syntax it lets you skip declaring the 'self' parameter and declares one behind the scenes.

Let's look at your three sample statements:

First statement:

local p1 = Z:Entity('New entity')

That is equivalent to this:

local p1 = Z.Entity(Z, 'New entity')

Since you set a metatable for Z.Entity with __call, you can use call the Entity table as a function. Since you use the colon syntax, it passes Z as the first parameter when calling the function so you are really passing two parameters. The way it is declared then, self will be Z.Entity and ... will expand to the two arguments, Z and 'New entity'.

Second statement:

p1 = Z.Entity.Create('test') 

Here you are simply calling the function 'Create' and passing it the string 'test' prints out Entity name: test. You are not using colon syntax and the metatable __call function isn't being executed because you are not calling Entity like a function.

Third statement:

p1 = Z:Entity.Create('test') 
-- lua: [string "<eval>"]:16: function arguments expected near '.' 

When you write Z:Entity, it expects you to be calling it as a function and it will pass Z as the first argument to that function. It doesn't make any sense to have a period following Entity.

Possible assumption

From the name Entity.Create, it sounds like you want to create a new object with this function and return it. This is where you would normally return a new table and call setmetatable and specify __index which will look for the the passed object to find functions that can be called. You should read up on object oriented programming in LUA, but here's a quick example of what I think you're trying to do:

Z = {
  Entity = {
    SayHello = function(self)
      print(self.name .. " says 'Hello'!")
    end,

    Create = function(name)
      local obj = {}
      obj.name = name
      setmetatable(obj, {__index = Z.Entity})
      -- now you can call obj:SayHello()
      return obj
    end
  }
}

local p1 = Z.Entity.Create('Player 1')

-- here p1 is passed as the first argument to SayHello because
-- a colon is used
p1:SayHello()  -- Player 1 says 'Hello'!
Jason Goemaat
  • 28,692
  • 15
  • 86
  • 113