Variable Store (as opposed to _G)

So, I recently decided that I would stop using a _G.ccp as a global storage table for my variables and instead use the recommended approach of requiring a module.

[lua]

variableStore = {}

return variableStore

[/lua]

However, I had problems with this. I called it in class A which uses the variableStore, which calls a method in class B. Class B also calls the variable store to do some processing work on variables entered in class A. It then returns a true or false to class A depending on if the work was successful. Simple, right?

Then I try to access one of the new variables created in class B from class A, its nil. Okay, I think to myself, I used [lua]local ccp = require(“variableStore”)[/lua], this means that I’m probably holding a copy of the table, so I need to get the most recent copy.

Enter new method in variableStore. [lua]variableStore.refresh = function()

    return variableStore

end[/lua]

Now, just before I try to access the data for the variableStore (via ccp[“status”]) I call [lua]ccp = ccp.refresh()[/lua] and get:

Runtime error

…Application Support/Outlaw/Sandbox/8/scene/login.lua:46: attempt to call field ‘refresh’ (a nil value)

Now, is any of the above expected behaviour? Is there a way to do this in a simpler fashion? (Like declare variable store as global in my main method, such as _ccp = require(“variableStore”)? ) Otherwise, I’m just going to change it back to using _G.ccp

It appears that if I call [lua]ccp = require(“variableStore”)[/lua] before or instead of ccp.refresh() then everything works again. Can someone explain why my ccp variable seems to stop working after being called from somewhere else and requires a new require?

Well so if local ccp equals the “variableStore” module then if you then go ccp = ccp.refresh then you overwrote the original ccp variable that contains the module.  If you went ccp = require"variableStore" and then lower down did local callMeAnythingOtherThanccp = ccp.refresh() then this would contain the new values.  I usually find its easier to require it once and then in class B have variableStore.variable1 = 0, variableStore.variable2 = 0 (or whatever initial values you want),  in class a do ccp.variable1 = 10, ccp.variable2 = 20, or local var = ccp.variable1, then you change or reference the variables on the fly.

Rob Miracle recently wrote an article on this topic, it should help: http://www.coronalabs.com/blog/2013/05/28/tutorial-goodbye-globals/

… Okay, I think to myself, I used [lua]local ccp = require(“variableStore”)[/lua], this means that I’m probably holding a copy of the table, so I need to get the most recent copy.

== first, this code:

[lua]local ccp = require(“variableStore”)[/lua]

doesn’t give you a *copy* of the table, it gives you the *real* (original) table… always. there’s no need to call refresh(). the parts of your code which have this line will be sharing a references to the same table thus you will instantly see changes anywhere you make them.

== second, you missed the important ‘local’ when declaring your variable store. without that, you’re essentially setting _G.variableStore, which is what you’re trying to avoid:

local variableStore = {} -- \<\<\<\< don't forget this 'local' -- refresh() is unneeded variableStore.refresh = function() print("in var store refresh") return variableStore end return variableStore

be sure to put ‘local’ in front of all of your variables when you first declare/define them, else they will be global. this could lead to unintended consequences and hard-to-find bugs (eg, perhaps ‘ccp’ being blown away somewhere else and needing to reset it with require() ). i’ve included an example below.

== third, i tried, but was unable to re-create your error. i used the following code:

[lua]
– main.lua

local varStore = require(“variableStore”)

print( varStore.a_var )
print( varStore.b_var )

local AClass = require(“aclass”)

print( varStore.a_var.this )
print( varStore.b_var )

local BClass = require(“bclass”)

print( varStore.a_var.this )
print( varStore.b_var.this )

varStore.refresh()

print( varStore.a_var.this )
print( varStore.b_var.this )

varStore.b_var.this=‘b_var changed in main’

print( varStore.a_var.this )
print( varStore.b_var.this )

print( aclass_var )
[/lua]

-- variableStore.lua local variableStore = {} -- refresh() is unneeded variableStore.refresh = function() print("in var store refresh") return variableStore end return variableStore

[lua]
– aclass.lua

local varStore = require(“variableStore”)

aclass_var = 45 – this is global, bad news !

varStore.a_var = { this=‘avar’}
[/lua]

[lua]
– bclass.lua

local varStore = require(“variableStore”)

varStore.b_var = { this=‘bvar’}
varStore.a_var.this=‘a_var changed in bclass’
[/lua]

-- output from main.lua, works as expected 2013-06-29 14:27:18.235 Corona Simulator[16594:f03] nil 2013-06-29 14:27:18.304 Corona Simulator[16594:f03] nil 2013-06-29 14:27:18.305 Corona Simulator[16594:f03] avar 2013-06-29 14:27:18.305 Corona Simulator[16594:f03] nil 2013-06-29 14:27:18.305 Corona Simulator[16594:f03] a\_var changed in bclass 2013-06-29 14:27:18.305 Corona Simulator[16594:f03] bvar 2013-06-29 14:27:18.306 Corona Simulator[16594:f03] in var store refresh 2013-06-29 14:27:18.306 Corona Simulator[16594:f03] a\_var changed in bclass 2013-06-29 14:27:18.306 Corona Simulator[16594:f03] bvar 2013-06-29 14:27:18.306 Corona Simulator[16594:f03] a\_var changed in bclass 2013-06-29 14:27:18.306 Corona Simulator[16594:f03] b\_var changed in main 2013-06-29 14:27:18.306 Corona Simulator[16594:f03] 45

what did you do differently ?

cheers,
dmc

@roaminggamer - Thank you, that is the article I read that caused me to decide to try using this method instead.

@Supertapp Interactive - It doesn’t appear to be something like that. For instance, a declared method seems to no longer work.

@dmccuskey - Thanks for catching that missing local, it didn’t solve the issue, but it does mean that I’m not doing it all pointlessly. When I refer to classes, I meant scenes. Let me put together some sample code and show you what I mean.

Edit: While making my test case, I realised that I’m an idiot. I managed to use ccp = {} in the enter scene event (leftover from a previous design). So ccp still existed as a table, but an empty one. Thanks for your help everyone, I would never have spotted this unless I was making a test case.

It appears that if I call [lua]ccp = require(“variableStore”)[/lua] before or instead of ccp.refresh() then everything works again. Can someone explain why my ccp variable seems to stop working after being called from somewhere else and requires a new require?

Well so if local ccp equals the “variableStore” module then if you then go ccp = ccp.refresh then you overwrote the original ccp variable that contains the module.  If you went ccp = require"variableStore" and then lower down did local callMeAnythingOtherThanccp = ccp.refresh() then this would contain the new values.  I usually find its easier to require it once and then in class B have variableStore.variable1 = 0, variableStore.variable2 = 0 (or whatever initial values you want),  in class a do ccp.variable1 = 10, ccp.variable2 = 20, or local var = ccp.variable1, then you change or reference the variables on the fly.

Rob Miracle recently wrote an article on this topic, it should help: http://www.coronalabs.com/blog/2013/05/28/tutorial-goodbye-globals/

… Okay, I think to myself, I used [lua]local ccp = require(“variableStore”)[/lua], this means that I’m probably holding a copy of the table, so I need to get the most recent copy.

== first, this code:

[lua]local ccp = require(“variableStore”)[/lua]

doesn’t give you a *copy* of the table, it gives you the *real* (original) table… always. there’s no need to call refresh(). the parts of your code which have this line will be sharing a references to the same table thus you will instantly see changes anywhere you make them.

== second, you missed the important ‘local’ when declaring your variable store. without that, you’re essentially setting _G.variableStore, which is what you’re trying to avoid:

local variableStore = {} -- \<\<\<\< don't forget this 'local' -- refresh() is unneeded variableStore.refresh = function() print("in var store refresh") return variableStore end return variableStore

be sure to put ‘local’ in front of all of your variables when you first declare/define them, else they will be global. this could lead to unintended consequences and hard-to-find bugs (eg, perhaps ‘ccp’ being blown away somewhere else and needing to reset it with require() ). i’ve included an example below.

== third, i tried, but was unable to re-create your error. i used the following code:

[lua]
– main.lua

local varStore = require(“variableStore”)

print( varStore.a_var )
print( varStore.b_var )

local AClass = require(“aclass”)

print( varStore.a_var.this )
print( varStore.b_var )

local BClass = require(“bclass”)

print( varStore.a_var.this )
print( varStore.b_var.this )

varStore.refresh()

print( varStore.a_var.this )
print( varStore.b_var.this )

varStore.b_var.this=‘b_var changed in main’

print( varStore.a_var.this )
print( varStore.b_var.this )

print( aclass_var )
[/lua]

-- variableStore.lua local variableStore = {} -- refresh() is unneeded variableStore.refresh = function() print("in var store refresh") return variableStore end return variableStore

[lua]
– aclass.lua

local varStore = require(“variableStore”)

aclass_var = 45 – this is global, bad news !

varStore.a_var = { this=‘avar’}
[/lua]

[lua]
– bclass.lua

local varStore = require(“variableStore”)

varStore.b_var = { this=‘bvar’}
varStore.a_var.this=‘a_var changed in bclass’
[/lua]

-- output from main.lua, works as expected 2013-06-29 14:27:18.235 Corona Simulator[16594:f03] nil 2013-06-29 14:27:18.304 Corona Simulator[16594:f03] nil 2013-06-29 14:27:18.305 Corona Simulator[16594:f03] avar 2013-06-29 14:27:18.305 Corona Simulator[16594:f03] nil 2013-06-29 14:27:18.305 Corona Simulator[16594:f03] a\_var changed in bclass 2013-06-29 14:27:18.305 Corona Simulator[16594:f03] bvar 2013-06-29 14:27:18.306 Corona Simulator[16594:f03] in var store refresh 2013-06-29 14:27:18.306 Corona Simulator[16594:f03] a\_var changed in bclass 2013-06-29 14:27:18.306 Corona Simulator[16594:f03] bvar 2013-06-29 14:27:18.306 Corona Simulator[16594:f03] a\_var changed in bclass 2013-06-29 14:27:18.306 Corona Simulator[16594:f03] b\_var changed in main 2013-06-29 14:27:18.306 Corona Simulator[16594:f03] 45

what did you do differently ?

cheers,
dmc

@roaminggamer - Thank you, that is the article I read that caused me to decide to try using this method instead.

@Supertapp Interactive - It doesn’t appear to be something like that. For instance, a declared method seems to no longer work.

@dmccuskey - Thanks for catching that missing local, it didn’t solve the issue, but it does mean that I’m not doing it all pointlessly. When I refer to classes, I meant scenes. Let me put together some sample code and show you what I mean.

Edit: While making my test case, I realised that I’m an idiot. I managed to use ccp = {} in the enter scene event (leftover from a previous design). So ccp still existed as a table, but an empty one. Thanks for your help everyone, I would never have spotted this unless I was making a test case.