Thread Tools Display Modes
08-05-14, 09:37 AM   #1
Haleth
This Space For Rent
 
Haleth's Avatar
Featured
Join Date: Sep 2008
Posts: 1,173
Table iteration question

I was cleaning up some of my code when I noticed something that might be obvious, but I didn't realise before: Attempting to access variables that do not exist by iterating a table and calling functions on them does not result in any errors.

For example:

Lua Code:
  1. for k, v in pairs({ThisDoesNotExist, NorDoesThis}) do v:Show() end

This doesn't cause any errors.

Why is this? I find it rather counter-intuitive. I'm now going over all my code where I attempt to access global variables through tables and making sure I do a _G lookup by name instead - otherwise, I never know when one of the frames I'm trying to access no longer exists.

Last edited by Haleth : 08-05-14 at 09:39 AM.
  Reply With Quote
08-05-14, 09:42 AM   #2
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,710
They do fail, only silently
  Reply With Quote
08-05-14, 09:49 AM   #3
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
It doesn't work exactly like I think that you think it does. What happens here is, when the variables are nil, there will be no entry created in the table, and so, nothing to iterate over. If both of those are nil, it will simply be an empty table.
__________________
Grab your sword and fight the Horde!
  Reply With Quote
08-05-14, 09:51 AM   #4
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Lombra View Post
It doesn't work exactly like I think that you think it does. What happens here is, when the variables are nil, there will be no entry created in the table, and so, nothing to iterate over. If both of those are nil, it will simply be an empty table.
Yep, the things inside the for loop wont even run, thats why there is no error.
However it's intresting, because you would expect that the pairs call would throw a nil error but it doesn't.
Probably there is a missing nil check in the pairs function, about it's intended or not i'm not sure.

Last edited by Resike : 08-05-14 at 09:57 AM.
  Reply With Quote
08-05-14, 10:30 AM   #5
Sharparam
A Flamescale Wyrmkin
 
Sharparam's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2011
Posts: 102
Originally Posted by Resike View Post
However it's intresting, because you would expect that the pairs call would throw a nil error but it doesn't.
Because there is no nil error in the call. {nil, nil} doesn't evaluate to nil, it evaluates to an empty table: {}. But since it has no values there is nothing to iterate over and the loop is "skipped".

Code:
> type({nil, nil})
'table'
> for _,_ in pairs(nil) do end
[string "local"]:1: bad argument #1 to 'pairs' (table expected, got nil)
> for _,_ in pairs({}) do end
> -- No output

Last edited by Sharparam : 08-05-14 at 10:34 AM. Reason: More examples
  Reply With Quote
08-05-14, 10:39 AM   #6
Haleth
This Space For Rent
 
Haleth's Avatar
Featured
Join Date: Sep 2008
Posts: 1,173
Tageshi: That's a possibility, but it seems a little wasteful using function calls for what can be done using just table lookups.

p3lim: That's what I was looking for, thank you! Sometimes the solution is easier than you expect it to be.
  Reply With Quote
08-05-14, 10:01 AM   #7
Haleth
This Space For Rent
 
Haleth's Avatar
Featured
Join Date: Sep 2008
Posts: 1,173
I see, thank you.

It's easy enough if my table contains only single frames - I can make sure they exist by using a _G lookup by name.

What if I'm also trying to refer frames that are table values of those frames, though?

Let's say I have something like this:

Code:
for _, bu in pairs({BonusFrame.RandomBGButton, BonusFrame.Arena1Button, BonusFrame.Arena2Button}) do
	bu.SelectedTexture:SetDrawLayer("BACKGROUND")
	bu.SelectedTexture:SetTexture(r, g, b, .2)
	bu.SelectedTexture:SetAllPoints()
end
What would be the correct syntax to ensure that both BonusFrame and its child members actually exist and that my code is executed?
  Reply With Quote
08-05-14, 10:07 AM   #8
Tageshi
A Murloc Raider
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 7
How about to re-write like this?
Code:
 
local function job1(bu)
	bu.SelectedTexture:SetDrawLayer("BACKGROUND")
	bu.SelectedTexture:SetTexture(r, g, b, .2)
	bu.SelectedTexture:SetAllPoints()
end
job1(BonusFrame.RandomBGButton);
job1(BonusFrame.Arena1Button);
job1(BonusFrame.Arena2Button);
  Reply With Quote
08-05-14, 10:11 AM   #9
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,710
Or this:
Lua Code:
  1. for _, method in pairs({'RandomBGButton', 'Arena1Button', 'Arena2Button'}) do
  2.     local bu = BonusFrame[method]
  3.     bu.SelectedTexture:SetDrawLayer("BACKGROUND")
  4.     bu.SelectedTexture:SetTexture(r, g, b, .2)
  5.     bu.SelectedTexture:SetAllPoints()
  6. end

I do exactly this for disabling the textures for the stock OverrideActionBar in my action bar addon:
https://github.com/p3lim-wow/pAction...rd.lua#L58-L75

Last edited by p3lim : 08-05-14 at 10:14 AM.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Table iteration question

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