How to declare a “variable variable” properly

Post Reply
User avatar
Linuxdirk
Member
Posts: 3219
Joined: Wed Sep 17, 2014 11:21
In-game: Linuxdirk
Location: Germany
Contact:

How to declare a “variable variable” properly

by Linuxdirk » Post

I am developing a helper mod. Mods depend on that mod and get an own “namespace” registered in the helper mod’s global table. The result is, that I have various tables in this table, like so:

Code: Select all

helper.mods.mod_1
helper.mods.mod_2
helper.mods.mod_3
helper.mods.mod_n
Each containing the mod’s defined functions and variables and so on.

One part of the helper mod is a function to convert this “semi-global” (because within the helper mod’s global table) individual mod’s tables into “real” global tables if the individual mod’s authors want that. I do this for not polluting the global namespace if not wanted/needed.

As I learned via research Lua maintains the global variables in the table _G. This allows adding “variable variables” like so:

Code: Select all

for name,value in pairs(helper.mods) do
    _G[name] = value
end
It results in the global variable named mod_1 having the value of helper.mods.mod_1, mod_2 of helper.mods.mod_2 and so on. This works perfectly and does exactly what I wanted to achieve (actually I first get the variables/mod name and do all the assignment stuff locally and then do one single _G[modname] = modvalues).

The only problem is that a warning gets triggered for every time I do this _G assignment.

Code: Select all

2018-05-17 17:59:45: WARNING[Main]: Assignment to undeclared global "[...]" inside a function at [...].
Which technically is correct because the global variable wasn’t declared before and I just declared it at this very moment.

So how to get rid of this error message? Is there a proper way to register a global variable in Minetest without knowing the variables name but only having a local variable holding the name of the to-be-created global variable?

User avatar
rubenwardy
Moderator
Posts: 6978
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy
Location: Bristol, United Kingdom
Contact:

Re: How to declare a “variable variable” properly

by rubenwardy » Post

It's quite bad practice to make globals which do not share the name of a mod. The reason for this is that you could end up with name collisions. Say the global you make is called mylib_noun. What if someone makes a mod called that and exposes a global? This is why it's recommended that mods only make globals with the same name as themself, hence the warning. (The other reason is that it's a sign of a typo, say assigning to defualt in the mod default)

If this mod is to automate making globals for mods then this isn't bad. I suggest registering the global whilst the corresponding mod is loading. IE: you can register "mod1" as a global without a warning whilst "mod1" is loading.
Spoiler
You can use rawset() to set a global without getting this error, but I very much recommend not doing that as it's a code smell.
Renewed Tab (my browser add-on) | Donate | Mods | Minetest Modding Book

Hello profile reader

User avatar
Linuxdirk
Member
Posts: 3219
Joined: Wed Sep 17, 2014 11:21
In-game: Linuxdirk
Location: Germany
Contact:

Re: How to declare a “variable variable” properly

by Linuxdirk » Post

rubenwardy wrote:If this mod is to automate making globals for mods then this isn't bad.
It is exactly that. The helper mod is a dependency and the mod whose author wants to make it an API calls the function to do so. The function reads the calling mod’s name, and creates the global from that name as described.

The function does some more stuff so it is not just a simple mymodname = my_local_api_table the mod author could do, but it does not create any globals that do not match the calling mod’s name. So collisions can’t happen unless someone else thinks, it would be a good idea to register a global with a name not matching the mod’s name. :)
rubenwardy wrote:I suggest registering the global whilst the corresponding mod is loading.
This is what I want to avoid. The global namespace is already polluted enough by mod authors that do not care about local. I only want to register a global if the mod author wants that.

The calls of the two relevant helper functions happen while the mod is loaded. One gets called before the mod’s actual code to initialize the mod (the tables and functions in order to use the helper system), and the other gets called after the mod’s actual code to clean up what was initialized. The second one has access to the tables created within the mod and is the one that optionally creates the global table.
rubenwardy wrote:IE: you can register "mod1" as a global without a warning whilst "mod1" is loading.
Mod authors can do `mod1 = 'foo'` in their code, yes. But how can I do within the helper function not knowing the mod’s name but only having a variable holding it - without doing this nasty rawset stuff I want to avoid?

User avatar
rubenwardy
Moderator
Posts: 6978
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy
Location: Bristol, United Kingdom
Contact:

Re: How to declare a “variable variable” properly

by rubenwardy » Post

not sure what you mean. There's a minetest.get_current_modname() function or similar though
Renewed Tab (my browser add-on) | Donate | Mods | Minetest Modding Book

Hello profile reader

User avatar
Linuxdirk
Member
Posts: 3219
Joined: Wed Sep 17, 2014 11:21
In-game: Linuxdirk
Location: Germany
Contact:

Re: How to declare a “variable variable” properly

by Linuxdirk » Post

rubenwardy wrote:not sure what you mean. There's a minetest.get_current_modname() function or similar though
Yes, and how to get a variable named after minetest.get_current_modname()? Except _G[minetest.get_current_modname()] of course.

Currently the un-cleaned, but working implementation looks like this.

https://github.com/4w/xtend/blob/abe2c8 ... ua#L62-L77

Post Reply

Who is online

Users browsing this forum: No registered users and 9 guests