Thread Tools Display Modes
11-18-12, 12:42 PM   #1
gmarco
An Onyxian Warder
 
gmarco's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2009
Posts: 362
Data structure suggestion

Hi, In my little addons I used a files categories.lua where the users define the custom mounts or pets to be summoned.

The structure is very simple:

Lua Code:
  1. mounts = {
  2.    
  3.    flying = {
  4.         "Draco Del Crepuscolo",
  5.         "Draco Rosso",
  6.         "Fenice Oscura",
  7.         "Proto-Draco Ferroso",
  8.    },
  9.    
  10.    ground = {
  11.         "Fiera della Luna Rapida",
  12.         "Fiera della Nebbia Rapida",
  13.         "Fiera della Notte Striata",
  14.  
  15.      },
  16.    
  17. [etc etc ...]
  18.  
  19. }

Now I'd like to try to move and replicate this data structure into the addons to use the WTF store method. But what I think was easy is not so easy.

Let's suppose I wanna add a mount in a category not yet defined with the syntax:

/mrc add new_category Swift Moonsaber

The parsing should be ok and suppose I have:

Lua Code:
  1. mounts = {}
  2. category="new_category"
  3. mount="Swift Moonsaber"

I thought that it could be simple as push a new entry in this way:

Lua Code:
  1. mounts[category][mount]=true

but here lua complain something about attempt to index field '?' (a nil value).

I try also with table.insert without any fortune.

I don't think things change so much removing one level ( categories[mount]=true ) being this to be pushed inside the mounts{} to be saved later.

Thanks in advance for your patience.
  Reply With Quote
11-18-12, 01:51 PM   #2
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
That's because you're doing it wrong. Here's what your code is currently doing:

Code:
mounts = {}
category="new_category"
mount="Swift Moonsaber"
  1. The first line creates the table { } and assigns it to the variable "mounts".
  2. The second line creates the string "new_category" and assigns it to the variable "category".
  3. The third line creates the string "Swift Moonsaber" and assigns it to the variable "mount".

Now when you do:

Code:
mounts[category][mount]=true
This is what's happening:
  1. The code looks for a table under the variable name "mounts". This returns the table, {}.
  2. The code looks for the value under the variable name "category" as a table key. This returns nil, because the "mounts" table is empty.
  3. The code looks for the value under the table returned by "mounts[category]". This fails and throws an error, because "mounts[category]" is nil, not a table.

What you need to do is:

Code:
local mounts = {}
local category = "new_category"
local mount = "Swift Moonsaber"

mounts[category] = {}
Then you can add values to the category the way you were trying to:

Code:
mounts[category][mount] = true
On a side note, you should never create global variables with such generic names as "mounts" and "category" and "mount". Such variables should always be declared as local. If you need those values to be accessible from other files, use your addon's private namespace (best) or give them distinct global names if absolutely necessary (last resort), such as "GimbolinoMounts" and "GimbolinoCategory". However, the only reasons to put anything in the global namespace are (1) it's a saved variable, or (2) you expect a need for it to be easily accessed from other addons, or (3) it's your main addon frame/table and you need to be able to easily access it in-game via "/run" commands for now for debugging purposes. If none of those apply, don't make it global.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
11-18-12, 05:08 PM   #3
gmarco
An Onyxian Warder
 
gmarco's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2009
Posts: 362
Originally Posted by Phanx View Post
That's because you're doing it wrong. Here's what your code is currently doing:

Code:
mounts = {}
category="new_category"
mount="Swift Moonsaber"
  1. The first line creates the table { } and assigns it to the variable "mounts".
  2. The second line creates the string "new_category" and assigns it to the variable "category".
  3. The third line creates the string "Swift Moonsaber" and assigns it to the variable "mount".

Now when you do:

Code:
mounts[category][mount]=true
This is what's happening:
  1. The code looks for a table under the variable name "mounts". This returns the table, {}.
  2. The code looks for the value under the variable name "category" as a table key. This returns nil, because the "mounts" table is empty.
  3. The code looks for the value under the table returned by "mounts[category]". This fails and throws an error, because "mounts[category]" is nil, not a table.

What you need to do is:

Code:
local mounts = {}
local category = "new_category"
local mount = "Swift Moonsaber"

mounts[category] = {}
Then you can add values to the category the way you were trying to:

Code:
mounts[category][mount] = true
Thanks Phanx,
I think I have finally understood :-)


On a side note, you should never create global variables with such generic names as "mounts" and "category" and "mount"...
Yes I know,
the above code was only a pseudo code I wrote to show the problem.
In the addon I surely use local for my names. :-)

Btw thanks for the great explanation on how the global var impact in the addon dataspace.

Now I an continue the rewrote :-)
  Reply With Quote
11-19-12, 08:48 AM   #4
Nimhfree
A Frostmaul Preserver
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 267
If you are letting people add mounts to categories, make sure the category does not already exist before you set the mounts[category] to the empty array. Something like:

if nil == mounts[category] then mounts[category] = {} end
mounts[category][mount] = true
  Reply With Quote
11-19-12, 03:40 PM   #5
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Or just mounts[category] = mounts[category] or {}
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
11-19-12, 04:37 PM   #6
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Nimhfree View Post
if nil == mounts[category] then
FYI, in Lua you do not need to explicitly check that something is equal to nil. You can just do:
if not mounts[category] then
...or you can make it more robust by checking its type instead:
if type(mounts[category]) ~= "table" then
The only reason you'd ever need to check that a value was equal to nil would be if you were using both nil and false values with different meanings, which isn't a very common scenario.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
01-13-13, 11:44 AM   #7
Sieben11
A Deviate Faerie Dragon
Join Date: Jan 2009
Posts: 10
Originally Posted by Seerah View Post
Or just mounts[category] = mounts[category] or {}
When reading this had the very same thought. I have always found that checking an item against itself before creation, to be much cleaner.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Data structure suggestion

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off