Your code does not contain "populated tables" to return.
Your newPlayer
function does create a table, and it does return it. It creates a number of functions within that table. But that's all newPlayer
does: creates a table and puts some functions in it.
The data accessed by those functions is not part of the table. n
, h
, a
, and r
(BTW, please use better variable names) are all local variables. Your inner functions will access the specific stack containing those variables, but the variables themselves will not be magically associated with the table.
Your principle problem is almost certainly with the setters. And it comes from a combination of this:
function player:setPlayerName(arg)
with this:
player1.getPlayerName()
When you create a function using a :
character between a table name and the function's name, you are using syntactic sugar for a function which implicitly takes as its first argument a value called self
. As the name suggests, this is supposed to represent the object which this function is being called upon. So your function creation code is equivalent to:
function player.setPlayerName(self, arg)
Since you create all of your functions with :
, all of your functions take at least one parameter.
The :
syntax can also be used when calling such functions. If you did player1:getPlayerName()
, this would cause the table you accessed to find the getPlayerName
function to be used as the first argument in the function call. So that line would be equivalent to player1.getPlayerName(player1)
.
Obviously, these two syntaxes are mirrors of one another: functions created with :
take a parameter that is expected to refer to the table it is being called on, and functions called with :
will be given the table which was accessed to get that function.
But... your code didn't stick to the symmetry. You created the functions with :
, but you call them with .
Now, you get
functions are able to get away with this because... well, none of your values are actually part of the table. So your get
functions just return the local value that they adopted from their creating context.
The set
functions pose a problem. See, they take a parameter. But because the function was declared with :
, they really take two parameters, the first being the implicit self
.
Now, :
syntax is just syntactic sugar; it's just a convenient way to do what you could have done yourself. So it is in theory OK to call a function with .
even if you created it with :
. But if you do so, you must pass the table as the first parameter. Though your code doesn't show it, I strongly suspect you didn't do that.
If you called player1.setPlayerName("foo")
, what will happen is that the implicit self
parameter will get the value "foo"
, and the arg
parameter will be nil
. And you will assign that nil
value to the n
local variable. So subsequent calls to player1.getPlayerName()
will return nil
.
Basically, what's going on here is that you're combining two different ways of creating objects in Lua. You stored your private data in a way that external code cannot access (ie: local upvalues), but that data is now no longer part of the table itself. Which means that, although you dutifully create those functions with :
syntax to indicate that they take a self
table, they never actually use that table. And because they never use the table, it's a lot harder to figure out what's going wrong.
Basically, the key here is to be symmetrical. If you create a function with :
, then you should either call it with :
or make sure to pass it the object table as the first parameter.
Broadly speaking, the standard way to create private members is by convention, not by forbidding it. That is, you agree not to mess with any members of a table other than those with certain names. Python convention is to pretend that names starting with _
don't exist, and Lua programs sometimes use that.
Upvalues are an interesting solution for private variables, but they do come with problems. If you want to invent a member variable, you have to do it in a centralized place rather than wherever you might need one. Even if the variable is optional, you have to create a named local
at the top of the function.