Iterate over all variables

Discussion of Lua and LuaWML support, development, and ideas.

Moderator: Forum Moderators

gfgtdf
Developer
Posts: 1432
Joined: February 10th, 2013, 2:25 pm

Iterate over all variables

Post by gfgtdf »

Hi i want to get a copy of the global wml variable set, to iterare over it, my first attempt was:

Code: Select all

local all_vars = wesnoth.get_variable("");
my second try was

Code: Select all

local H = wesnoth.require "lua/helper.lua"
local V = H.set_wml_var_metatable {}
for k,v in pairs(V) do
	wesnoth.wml_actions.wml_message {logger = "err", message = k }
end
however that doesn't seem to work. Does someone else know how to do it ?
(I dont care whether in lua or in wml)
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
User avatar
Elvish_Hunter
Posts: 1575
Joined: September 4th, 2009, 2:39 pm
Location: Lintanir Forest...

Re: Iterate over all variables

Post by Elvish_Hunter »

gfgtdf wrote:however that doesn't seem to work. Does someone else know how to do it ?
(I dont care whether in lua or in wml)
That's an interesting question, so I started investigating.
The game already has a place where all the variables are shown in one go: the gamestate inspector window. Here, there is an interesting chunk:

Code: Select all

227  const config& vars = resources::gamedata
228  ? resources::gamedata->get_variables()
229  : config();
Apparently, the C++ engine already supports fetching all the available variables, but this function (as a grep for "get_variables" reveals) was never exposed to Lua or WML:

Code: Select all

carryover.cpp:	variables_ = gamedata.get_variables();
carryover.hpp:	const config& get_variables() const { return variables_; }
game_data.hpp:	const config& get_variables() const { return variables_; }
gui/dialogs/gamestate_inspector.cpp:						 ? resources::gamedata->get_variables()
gui/dialogs/gamestate_inspector.cpp:						 ? resources::gamedata->get_variables()
persist_var.cpp:		const config &vars = resources::gamedata->get_variables();
variable.cpp:	BOOST_FOREACH(const config &i, resources::gamedata->get_variables().child_range(var_name_)) {
So, currently there is no way to do what you want, but I suppose that a wesnoth.get_variables() Lua function may be implemented; how easily, I have no idea yet (even the stones know that I always struggle with C++... :oops: ).
Current maintainer of these add-ons, all on 1.16:
The Sojournings of Grog, Children of Dragons, A Rough Life, Wesnoth Lua Pack, The White Troll (co-author)
gfgtdf
Developer
Posts: 1432
Joined: February 10th, 2013, 2:25 pm

Re: Iterate over all variables

Post by gfgtdf »

ty, i was hoping for a solution that is available in 1.12 but that doesn't seem possible.

It looks like it need to be implemented in 1.14.

Maybe we can have something similar to luas _G as a reference to the global table so the wesnoth.get_variable("_G") returns the global variable table, and wesnoth.get_variable("_G.somevalue.someonthervalue") will then be equal to wesnoth.get_variable("somevalue.someonthervalue").

maybe that would work in a situation like [set_variable] name = "a", value = "$_G" [/set_variable] too then.

A related question: do we support empty strings as wmtags like

Code: Select all

[]
  somevalue = "ooo"
[/]
or empty attributes like

Code: Select all

[sometag]
   = "ooo"
[/sometag]
?
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
User avatar
iceiceice
Posts: 1056
Joined: August 23rd, 2013, 2:10 am

Re: Iterate over all variables

Post by iceiceice »

gfgtdf wrote: Maybe we can have something similar to luas _G as a reference to the global table so the wesnoth.get_variable("_G") returns the global variable table
Could also just make a new function "wesnoth.get_all_variables()". (Or maybe "wesnoth.get_variable_set" and then define various behaviors when you give it args...)
gfgtdf wrote: do we support empty strings as wmltags or empty attributes
From source inspection I think the answer is no.

The tokenizer defines a "string" token as beginning when it finds a leading alphanumeric character:

https://github.com/wesnoth/wesnoth/blob ... r.cpp#L143

If the parser doesn't find a string inside of a [ ] tag, and can't interpret it with + addition tag, or / end tag syntax, it's going to report an error here:

https://github.com/wesnoth/wesnoth/blob ... r.cpp#L225

Similarly if you use empty variable names, you can expect errors here and here:

https://github.com/wesnoth/wesnoth/blob ... r.cpp#L245

https://github.com/wesnoth/wesnoth/blob ... r.cpp#L257

I think it's probably by design. For instance, the parser isn't totally whitespace insensitive, you cannot insert line breaks into your code at random

Code: Select all

    a
        = 1239502348
is not parsed the same as

Code: Select all

    a = 1239502348
If we allowed empty variable names I bet there would be corner cases where malformed code might not fail to parse as we want it to.
gfgtdf
Developer
Posts: 1432
Joined: February 10th, 2013, 2:25 pm

Re: Iterate over all variables

Post by gfgtdf »

i don't like implementing this as a lua function i'd liek to implement inside variable_info, so i can also ue it in code like:

Code: Select all

   [set_global_variable]
     namespace=my_addon
     from_local=$_G
     to_global=my_variable_name
   [/set_global_variable]
another option besides "_G" could be a "_self" which like 'undoes the dot'.


Does anyone know what the "__array" and "__value" string in here do?
https://github.com/wesnoth/wesnoth/blob ... e.cpp#L582
it looks liek they have been introduced in this commit:
https://github.com/wesnoth/wesnoth/comm ... 9a0d1a4c36
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
User avatar
iceiceice
Posts: 1056
Joined: August 23rd, 2013, 2:10 am

Re: Iterate over all variables

Post by iceiceice »

What exactly is your use case for this?

Note that it pretty much goes directly against the idea here: http://forums.wesnoth.org/viewtopic.php ... 68#p572369

It's much easier for add-ons to work together without problems if they are unaware of what eachother are doing. If your add-on's behavior is sensitive to what variables other add-ons are using, it means that if I use your add-on with some other modification, it could create a bug that is very difficult to untangle. Think about it -- with simple add-ons I know that they only communicate via shared variables / the units on the map. If I want to know if a variable is shared, I can search the files for the name -- variables can point to other variables, but pretty much at some point the string (or at least, my prefix) has to appear explicitly. If you can just get a run-time list of all current variables, though, then I basically have to read all of the code to figure out what variables it is using. So in general using something like this would probably not be recommended (in my view) even if it existed.

Is it your intention to use this to discover the variables of other add-ons at run-time using this mechanism? If not, you know the names of the variables that *you* are using, so why do you need to rediscover them at run time? IMO encapsulation is usually a good thing.
gfgtdf
Developer
Posts: 1432
Joined: February 10th, 2013, 2:25 pm

Re: Iterate over all variables

Post by gfgtdf »

iceiceice wrote: Is it your intention to use this to discover the variables of other add-ons at run-time using this mechanism?
yes this is exactly what i want, i told you the intention on irc yesterday.
iceiceice wrote: Note that it pretty much goes directly against the idea here: http://forums.wesnoth.org/viewtopic.php ... 68#p572369
i don't think the "_self" or "_G" goes much more against this than a lua function.
if we really implemented 'per addon' variabel scopes which is not what i would support unless i see a clear solution that does not make it too hard for addons to commuicate via variables and also gives good solution to how do variables bahave if 'event by addon 1 fires an event made by addon 2' and similar.
then "_self" would most likeley still just 'undo the dot' which makes it unusable for my case but not nesecarily a bad feature. I think in case tha happens we can still implement it as a lua function.
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
User avatar
iceiceice
Posts: 1056
Joined: August 23rd, 2013, 2:10 am

Re: Iterate over all variables

Post by iceiceice »

Here was our irc conversation:
irc wrote: 20140627 22:31:57< gfgtdf> iceiceice: i wanted to make a OOS check [modification] add on that checks whether the variabels are equal on all clients at turn start
20140627 22:32:28< iceiceice> why not just write it in C++?
20140627 22:32:48< gfgtdf> iceiceice: i want it in 1.12
If you've now decided it can't be in 1.12, I'll say again, it's just my opinion but it's better not even to have the lua function version and to write something like this in C++. You are trying to write a debugger which needs special privileges over the other add-ons, and to do it your plan is to just give these abilities to all add-ons...

I guess there are plenty of cases where we make "features" that are really guns you can use to blow your foot off, (case in point: custom lua report code that can execute arbitrary changes to the game state while it's just supposed to be helping to draw the gui) and tell the users "go nuts with it", after all the beginners will hopefully stay away from it. But then a lot of users get unhappy when they don't have any feet. :hmm:

Edit: The thing is it's more of a problem when your code is supposed to also be used with *other people's* code, code which you cannot predict, because then accidents are much more likely and harder to predict.

My opinion is that this feature is likely to cause more problems than it solves, and those problems can be solved other ways so why bother with it.

Do you really want to be the one to provide support for all the bizarre stuff people will inevitably use this for and the problems that will result?
User avatar
Sapient
Inactive Developer
Posts: 4453
Joined: November 26th, 2005, 7:41 am
Contact:

Re: Iterate over all variables

Post by Sapient »

gfgtdf wrote: Does anyone know what the "__array" and "__value" string in here do?
https://github.com/wesnoth/wesnoth/blob ... e.cpp#L582
it looks liek they have been introduced in this commit:
https://github.com/wesnoth/wesnoth/comm ... 9a0d1a4c36
That's what happens when you try to use an explicit index of an array as if it were an array or a scalar and force_valid is true. You can't store a scalar to a container without a key name (thus __value). You can't store an array to an explicit index of an another array without a sub-array name (thus __array). But these are hidden implementation details that should not be relied upon to remain true. A WML author should never have to use a variable name that starts with an underscore. This magic underscore idea is something that goes against WML's design. So I'd rather it be accessed with a simple non-cryptic name if it's to be exposed to WML, e.g. "all_game_variables" or even just "variables"
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
gfgtdf
Developer
Posts: 1432
Joined: February 10th, 2013, 2:25 pm

Re: Iterate over all variables

Post by gfgtdf »

Sapient wrote:
gfgtdf wrote: Does anyone know what the "__array" and "__value" string in here do?
https://github.com/wesnoth/wesnoth/blob ... e.cpp#L582
it looks liek they have been introduced in this commit:
https://github.com/wesnoth/wesnoth/comm ... 9a0d1a4c36
That's what happens when you try to use an explicit index of an array as if it were an array or a scalar and force_valid is true. You can't store a scalar to a container without a key name (thus __value). You can't store an array to an explicit index of an another array without a sub-array name (thus __array). But these are hidden implementation details that should not be relied upon to remain true. A WML author should never have to use a variable name that starts with an underscore. This magic underscore idea is something that goes against WML's design. So I'd rather it be accessed with a simple non-cryptic name if it's to be exposed to WML, e.g. "all_game_variables" or even just "variables"
So changing this code into giving a wml error in this case is ok ?
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
User avatar
Sapient
Inactive Developer
Posts: 4453
Joined: November 26th, 2005, 7:41 am
Contact:

Re: Iterate over all variables

Post by Sapient »

It already prints to WRN_NG. If force_valid is true then the function is guaranteed to return a usable variable reference. You shouldn't violate that post-condition. Otherwise callers would have to force_valid_unless_illegal then branch on another boolean is_illegal as an additional step... surely a less attractive option.

But you could, for example, return a reference from resources::gamedata->temporaries_ with the original (illegal) variable name. This is what happens when they use a reserved keyword, i.e. array.length. Then, rather than having __array/__value in the :inspect/game saves, they'd have nothing at all for that variable.
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
gfgtdf
Developer
Posts: 1432
Joined: February 10th, 2013, 2:25 pm

Re: Iterate over all variables

Post by gfgtdf »

hm so if the passed string is like "[[[..[)))?]..." the function still returns a (undefined) valid reference ?
what is the reason against using exceptions ?
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
User avatar
Elvish_Hunter
Posts: 1575
Joined: September 4th, 2009, 2:39 pm
Location: Lintanir Forest...

Re: Iterate over all variables

Post by Elvish_Hunter »

gfgtdf wrote:Maybe we can have something similar to luas _G as a reference to the global table so the wesnoth.get_variable("_G") returns the global variable table
While for a Lua coder may make sense, for a WML coder having a variable called _G will be something like Moon Logic: completely unobvious, it'll start making sense only if and when our UMC author starts learning Lua.
iceiceice wrote:Could also just make a new function "wesnoth.get_all_variables()"
That's what I did, although I called it get_all_vars because it's shorter. Feel free to rename it, if you want. ;)
By the way: pushed in master, b0b40ebe86e4.
Current maintainer of these add-ons, all on 1.16:
The Sojournings of Grog, Children of Dragons, A Rough Life, Wesnoth Lua Pack, The White Troll (co-author)
User avatar
iceiceice
Posts: 1056
Joined: August 23rd, 2013, 2:10 am

Re: Iterate over all variables

Post by iceiceice »

gfgtdf wrote:hm so if the passed string is like "[[[..[)))?]..." the function still returns a (undefined) valid reference ?
what is the reason against using exceptions ?
I would also like to the know the answer to this.

Is it generally okay to throw exceptions in lua api functions, or does that cause memory leaks in the lua kernel? My assumption is the latter since iiuc the lua kernel is pure C.
Anonymissimus
Inactive Developer
Posts: 2461
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: Iterate over all variables

Post by Anonymissimus »

iceiceice wrote:Is it generally okay to throw exceptions in lua api functions, or does that cause memory leaks in the lua kernel? My assumption is the latter since iiuc the lua kernel is pure C.
By "lua kernel" you are referring to our embedded lua code ? Yes, it's C.

I would say throwing exceptions anywhere in C++ should be avoided in general, because it is too dangerous, as opposed to java. In these lua api functions, there's the lua stack, where things get pushed and popped. When the function runs out, everything that was pushed should have been popped again and vice versa.
I once fixed a bug where something was popped that had never been pushed. Very annoying effects, very hard to find and fix, only sometimes reproducible and under certain conditions etc.
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml startersPlan Your Advancements: mp mod
The Earth's Gut: sp campaignSettlers of Wesnoth: mp scenarioWesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
Post Reply