Search code examples
luatostring

How can I override to __tostring of a metatable in a Lua class?


I have this class:

math.randomseed(os.time())
local Die = {}

function Die.new(side)
  if side ~= 4 or side ~= 6 or side ~= 8 or side ~= 10 or side ~= 12 or side ~= 10 or side ~= 100 then
    side = 6
  end
  ran = math.random(side)       -- had to get the value before placing in table
  local self = { numSides = side, currentSide = ran}

  local getValue = function(self)
    return self.currentSide
  end

  local roll = function(self)
    self.currentSide = math.random(self.numSides)
  end

  local __tostring = function(self) 
    return "Die[sides: "..self.numSides..", current value: "..self.currentSide.."]" 
  end

  return {
    numSides = self.numSides,
    currentSide = self.currentSide,
    getValue = getValue,
    roll = roll,
    __tostring = __tostring
  }
end

return Die

My goal is when I use the line print(dieOne), for example, is to have the __tostring print out the data. Currently, my __tostring doesn't work, but I'm pretty sure I'm trying to do this the wrong way.

How can I achieve this? Thanks!


Solution

  • The __tostring entry must exist in the metatable of every instance you return from Die.new. Currently, you're only storing it as an ordinary entry. Here's how you can ensure it's correctly saved in each associated metatable:

    function Die.new(side)
      -- as before...
    
      -- setup the metatable
      local mt = {
        __tostring = __tostring
      }
    
      return setmetatable({
        numSides = self.numSides,
        currentSide = self.currentSide,
        getValue = getValue,
        roll = roll,
      }, mt)
    end
    

    Here, we leverage the fact that setmetatable not only does what its name suggests but also returns the first function argument.

    Note that there is no need to call the function itself __tostring. Only the metatable key must be "__tostring".