Packaging local variables / debug library dangers

I have a lua file containing lots of variables which I intend to reuse a lot (most of them store colour tables).  So I might (ideally) have a long list that reads something like:-

[lua]

local purple = {0.8, 0.1, 0.7}

local teal = {0.05, 0.6, 0.5}

[/lua]

etc.

I have come across a circumstance where I would like to access these in another module in the simplest way possible. I’m fully aware that the normal way of doing this would be to store them in a table module, do local var = require (“scripts.variables”), and refer to them as (say) var.teal, var.purple etc…  However that looks a lot uglier, is harder to read and is slower to type.  I’m using these variables to create levels, and the quicker / easier it is to edit, the easier my life will be when fine tuning.

I wondered whether there was a way of packing and unpacking local scope variables (in a similar way to using _G to access globals).  I have two questions:-

  1. I’ve found a way to package the locals into a table using debug.getlocal.  I thought I was on my way to a solution for the “unpacking” part using the debug library (debug.setlocal).  However, on closer inspection this only seems to be able to change local variables which have already been declared.  Is that right?  Is my quest fruitless?

  2.  In any event I see lots of warnings about using the debug library in finished code, without much explanation around the dangers.  Is this really something to be concerned about?  My proposed use for it seems pretty innocuous but I would be interested to know if anyone else “resorts” to using the debug library in this way.

Why not localize?

common.lua

local common = {} common.someReallyLongVariableNameForWhateverReason = { 1, 2, 3, 4, 5 } return common

bob.lua

local common = require "common" local shortRef = common.someReallyLongVariableNameForWhateverReason print(shortRef[1])

i know how to localise a table of variables, that’s not the issue. and the length of the variable names is not that big an issue. most will be 10 characters max. it’s ease of editing / reading that’s the main issue. It’s a long list of variables, which I need to access from multiple modules. level data (one of the modules which needs access) will take the form of arrays of these variables. I will be constantly tweaking the list of variables and the level data. to give an example, which of these is easier to read and see at a glance what’s going on: [lua] LevelData[1] = { selection = { teal, aubergine, purple, taupe }, target = { teal, aubergine, taupe } } LevelData[1] = { selection = { var.teal, var.aubergine, var.purple, var.taupe }, target = { var.teal, var.aubergine, var.taupe } } [/lua] if it was 10 or 20 variables, no big deal to localise each one separately (e.g. local teal = var.teal) however it’s going to be a much longer list and one I expect to add to. what I could really do with is a function which takes a table full of keys like var.teal and var.purple and automatically unpacks them into local scope variables with the names teal and purple.

How about you switch your ‘selection’ and ‘target’ stuff and make an intermediate “preprocessing” step to get the correct colors from it?

Something like a fancier version of this:

LevelData[1] = { selection = {"teal", "aubergine", "purple", "taupe"}, target = {"teal", "aubergine", "taupe"} } -- Later for l = 1, #LevelData do for i = 1, #LevelData[l].selection do LevelData[l].selection[i] = var[LevelData[l].selection[i] ] end for i = 1, #LevelData[l].target do LevelData[l].target[i] = var[LevelData[l].target[i] ] end end

That way, we say that each element in ‘selection’ and ‘target’ is meant to be a string key of the associated element in ‘var’.

  • Caleb

I think Caleb’s approach is the “closest” you’re likely to get, though you perhaps take it one tiny step further, if you needed to save making ANY change to your level definitions, and preface it with (abbreviated):

local teal = “teal”

local aubergine = “aubergine”

– et cetera

now lines 2-4 of your code (the level definition) can remain the same, but lines 7-10 of your code (the level building) can look like Caleb’s. [EDIT:  there a sarcastic “futility” implied here that might? not be obvious:  cuz if you were willing to manually define all those locals as strings, then why not just define them as your color tables, right?  granted]

[to your original question as asked:  you can’t natively access/create locals like you can globals in some table somewhere, otherwise you could just do a local equivalent of “local colornames = require(“colornames”) for k,v in pairs(colornames) do _G[k]=v end” to populate that table with your locals, BUT there is no equivalent “_L” table for creating those locally akin to the global _G table, in fact locals don’t even have key names to begin with - instead they’re accessed by numeric index.  i personally wouldn’t use the debug library in production code.]

Thanks, that’s a good suggestion Caleb, much closer to what I’m trying to do. I’ll just have to accept that setlocal doesn’t do what I hoped! it’s sparked my interest in the debug library though, a library I’d not really explored before.

@epicurus101,

Tip:  debug.* functions (setlocal(), etc.)  will only work on the simulator anyways.  The debug library is stripped out of device builds.

Don’t fall into that trap.  I’ve been there and it was a painful lesson.

PS - Understanding this library is useful, just don’t use it to build features you rely upon for your game/app and expect them to work in the release.  As the name implies, that is just for debug(ging) code.

OK, thanks Ed, that’s a very powerful reason not to get too interested in it!

Why not localize?

common.lua

local common = {} common.someReallyLongVariableNameForWhateverReason = { 1, 2, 3, 4, 5 } return common

bob.lua

local common = require "common" local shortRef = common.someReallyLongVariableNameForWhateverReason print(shortRef[1])

i know how to localise a table of variables, that’s not the issue. and the length of the variable names is not that big an issue. most will be 10 characters max. it’s ease of editing / reading that’s the main issue. It’s a long list of variables, which I need to access from multiple modules. level data (one of the modules which needs access) will take the form of arrays of these variables. I will be constantly tweaking the list of variables and the level data. to give an example, which of these is easier to read and see at a glance what’s going on: [lua] LevelData[1] = { selection = { teal, aubergine, purple, taupe }, target = { teal, aubergine, taupe } } LevelData[1] = { selection = { var.teal, var.aubergine, var.purple, var.taupe }, target = { var.teal, var.aubergine, var.taupe } } [/lua] if it was 10 or 20 variables, no big deal to localise each one separately (e.g. local teal = var.teal) however it’s going to be a much longer list and one I expect to add to. what I could really do with is a function which takes a table full of keys like var.teal and var.purple and automatically unpacks them into local scope variables with the names teal and purple.

How about you switch your ‘selection’ and ‘target’ stuff and make an intermediate “preprocessing” step to get the correct colors from it?

Something like a fancier version of this:

LevelData[1] = { selection = {"teal", "aubergine", "purple", "taupe"}, target = {"teal", "aubergine", "taupe"} } -- Later for l = 1, #LevelData do for i = 1, #LevelData[l].selection do LevelData[l].selection[i] = var[LevelData[l].selection[i] ] end for i = 1, #LevelData[l].target do LevelData[l].target[i] = var[LevelData[l].target[i] ] end end

That way, we say that each element in ‘selection’ and ‘target’ is meant to be a string key of the associated element in ‘var’.

  • Caleb

I think Caleb’s approach is the “closest” you’re likely to get, though you perhaps take it one tiny step further, if you needed to save making ANY change to your level definitions, and preface it with (abbreviated):

local teal = “teal”

local aubergine = “aubergine”

– et cetera

now lines 2-4 of your code (the level definition) can remain the same, but lines 7-10 of your code (the level building) can look like Caleb’s. [EDIT:  there a sarcastic “futility” implied here that might? not be obvious:  cuz if you were willing to manually define all those locals as strings, then why not just define them as your color tables, right?  granted]

[to your original question as asked:  you can’t natively access/create locals like you can globals in some table somewhere, otherwise you could just do a local equivalent of “local colornames = require(“colornames”) for k,v in pairs(colornames) do _G[k]=v end” to populate that table with your locals, BUT there is no equivalent “_L” table for creating those locally akin to the global _G table, in fact locals don’t even have key names to begin with - instead they’re accessed by numeric index.  i personally wouldn’t use the debug library in production code.]

Thanks, that’s a good suggestion Caleb, much closer to what I’m trying to do. I’ll just have to accept that setlocal doesn’t do what I hoped! it’s sparked my interest in the debug library though, a library I’d not really explored before.

@epicurus101,

Tip:  debug.* functions (setlocal(), etc.)  will only work on the simulator anyways.  The debug library is stripped out of device builds.

Don’t fall into that trap.  I’ve been there and it was a painful lesson.

PS - Understanding this library is useful, just don’t use it to build features you rely upon for your game/app and expect them to work in the release.  As the name implies, that is just for debug(ging) code.

OK, thanks Ed, that’s a very powerful reason not to get too interested in it!