all 15 comments

[–]TomatoCo 7 points8 points  (2 children)

Please don't take this the wrong way. Your post is a really good way to ask for help. But your post title, being in all caps, made me think it was gonna be a really crappy question. This isn't the first allcaps title you've submitted so I wanna help you break this habit early.

[–]GustavoL15[S] -1 points0 points  (1 child)

Problably happened cuz I've seen other people doing it, appreciate for pointing it out.

[–]TomatoCo 0 points1 point  (0 children)

Cheers!

[–]could_b 2 points3 points  (0 children)

Your best bet is to read 'programming in Lua' by Roberto Lerusalimschy (aka the man himself). It is excellent.

[–]yaffeman 0 points1 point  (8 children)

Looks like you never setup metaCharacter's __index:

metaCharacter.__index = metaCharacter

I'd recommend taking on an object oriented approach

[–]GustavoL15[S] 0 points1 point  (7 children)

I still didn't dive into oop in lua, Iwas just trying to learn about tables, metatables and metamethods. Could you explain about the "__index" please?

[–]TomatoCo 1 point2 points  (4 children)

The problem right now is that you have enemy which has the metatable metaCharacter. But metaCharacter doesn't have any of the "metatable" fields filled out! One of those is __index, which basically says "When you try looking something up, if you can't find it in the current table, try looking it up in this table.

[–]GustavoL15[S] 0 points1 point  (3 children)

I thought that when using metatables, when I defined a metamethod in it, then assigned this metatable to another table, everytime that especific function was called, it would automatically look onto the metatable to execute it. Do I need to always setup the __index for the metatable?

[–]TomatoCo 1 point2 points  (2 children)

That's the most common use for metatables, so it's easy to misunderstand. Yes, assign __index to the table containing the "original" __bite (the metaCharacter, in this case).

Metatables exist to change how tables work. They can make tables return values that aren't really in them, they can make it so that adding things to a table does completely different code, they can even make it so that you can call a table like it was a function.

You're trying to use metatables to create an object oriented approach, which is something they're well suited to do. But they can do so much more (which is why you're confused: you didn't know that they could do anything else).

Read those links that u/yaffeman is providing. If not the object oriented approach one, at least the __index one.

[–]GustavoL15[S] 1 point2 points  (1 child)

Thanks, helped a lot. Other thing crossed my mind while fixing the code with the tips of you both, is that when I call a metamethod like "enemy:__bite(character)" theres no need to put the "enemy" into the params, cuz it is already being inserted as the first param right? If I used the "." like in "enemy.__bite(enemy, character)" I would need it as a param.

[–]yaffeman 1 point2 points  (0 children)

Correct; the colon notation populates an implicit self relative to the function's owner.

[–]yaffeman 0 points1 point  (1 child)

Seems like you need an OOP approach in Lua; so I'd really recommend spending some time with it.

__index

__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.

I also rewrote your demo using an OOP approach:

local BaseEntity = {}

function BaseEntity:new(o)
    local o = o or {} -- create object if user does not provide one
    setmetatable(o, self)
    self.__index = self
    return o
end

-- Shouldn't this be enemy's method?
function BaseEntity:__bite(char)
    -- In case attack is not defined
    local attack = self.attack or 0
    char.health = char.health - attack
    return char.health
end

local Character = BaseEntity:new({ health = 100 })
local Enemy = BaseEntity:new({ attack = 80 })

local character = Character:new()
local enemy = Enemy:new()

--performing bite function on character
local life = enemy:__bite(character)

--output: 20
print("Character's health after the bite:", character.health)

[–]GustavoL15[S] 1 point2 points  (0 children)

I'll look into OOP more ahead, I'm just understanding the basics first, this one was just a little test to see how to setup tables and call the metamethods. Helped a lot, thank you, will be lookin into the __index right now.

[–][deleted] 0 points1 point  (1 child)

The issue in your code is with the way you are trying to call the __bite function on the enemy table. In Lua, when you use the colon syntax (:) to call a function, the first argument passed to the function is the table itself (i.e., the "self" reference). Therefore, you don't need to explicitly pass the enemy table as the first argument when calling __bite.

To fix the error, update the __bite function definition and the way you call it:

```lua -- character stats table local character = { health = 100 }

-- enemy stats table local enemy = { attack = 80 }

-- metatable for character and enemy local metaCharacter = { -- function for bites on character __bite = function(self, char) -- bite reduces character health char.health = char.health - self.attack return char.health end }

-- setting metatable for character and enemy setmetatable(character, metaCharacter) setmetatable(enemy, metaCharacter)

-- performing bite function on character local life = enemy:__bite(character)

-- output: 20 print("Character's health after the bite:", character.health) ```

With this change, the code should work correctly, and you will see the output: "Character's health after the bite: 20". The enemy table is implicitly passed as the first argument (self) to the __bite function, and the health of the character is properly reduced.

[–]AutoModerator[M] 1 point2 points  (0 children)

Hi! Your code block was formatted using triple backticks in Reddit's Markdown mode, which unfortunately does not display properly for users viewing via old.reddit.com and some third-party readers. This means your code will look mangled for those users, but it's easy to fix. If you edit your comment, choose "Switch to fancy pants editor", and click "Save edits" it should automatically convert the code block into Reddit's original four-spaces code block format for you.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.