Thread Tools Display Modes
08-10-08, 06:30 AM   #1
kerrang
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Oct 2006
Posts: 109
Emptying a Table

Here's a challenge for you

Fred = {}
Fred['barney'] = {}
Fred['barney']['wilma'] = "Flintstone"
Fred = nil
Fred = {}
Fred['barney'] = {}

What does Fred['barney']['wilma'] now contain

Clue: It's not nil, "" nor does it not exist

How does one actually empty a table then?
  Reply With Quote
08-10-08, 07:33 AM   #2
Slakah
A Molten Giant
 
Slakah's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2007
Posts: 863
Originally Posted by kerrang View Post
Here's a challenge for you

Fred = {}
Fred['barney'] = {}
Fred['barney']['wilma'] = "Flintstone"
Fred = nil
Fred = {}
Fred['barney'] = {}

What does Fred['barney']['wilma'] now contain

Clue: It's not nil, "" nor does it not exist

How does one actually empty a table then?
Code:
Fred = {}
Fred['barney'] = {}
print(Fred['barney'])
Fred['barney']['wilma'] = "Flintstone"
Fred = nil
Fred = {}
Fred['barney'] = {}
print(Fred['barney'])
print(Fred['barney']['wilma'])
outputs
Code:
table: 0036B180
table: 0036B290
nil
  Reply With Quote
08-10-08, 07:57 AM   #3
LBXZero
A Theradrim Guardian
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 61
I believe it should be nil unless you have a local variable in a block using the same name. Then for that block it will fool you.

If Fred is a global, you can also setglobal("Fred",nil).
  Reply With Quote
08-10-08, 08:09 AM   #4
kerrang
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Oct 2006
Posts: 109
Post

In my case, Fred is declared at the highest level within my addon - it's actually a 'savedvariable' too.

After

Fred = {}
Fred['barney'] = {}
print(Fred['barney'])
Fred['barney']['wilma'] = "Flintstone"
Fred = nil
Fred = {}
Fred['barney'] = {}
print(Fred['barney']['wilma'])

results in "Flintstone"

I've actually changed

Fred = nil

to

for val = pairs(Fred) do
for val2 in pairs(Fred[val]) do
Fred[val][val2] = nil
end
end
Fred = nil

and that resets it...

Something related to the way SavedVariables work perhaps?
  Reply With Quote
08-15-08, 05:26 PM   #5
kerrang
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Oct 2006
Posts: 109
I've come across a second instance where emptying a table isn't actually emptying it - in that recreating a key which existed before will bring back values previous held for that key...

This time it's not a savedvariable but it is defined at the highest level of the addon's scope.

I can only assume this is a bug in the Blizzard lua implementation?

The statement

mytable = {}

SHOULD clear EVERYTHING in the existing table should it not?
  Reply With Quote
08-16-08, 08:41 AM   #6
LBXZero
A Theradrim Guardian
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 61
If I understand what you are saying, try this for cleaning the table. Create a dummy variable with a new blank table and set your global variable to that blank table.

Code:
local blanktable = {};
setglobal("fred",blanktable);
I am just thinking this up, so I really have not tried it nor can immediately comfirm if it will run.
  Reply With Quote
08-21-08, 09:08 PM   #7
arkayenro
A Deviate Faerie Dragon
AddOn Author - Click to view addons
Join Date: Dec 2006
Posts: 12
Originally Posted by kerrang View Post
mytable = {}

SHOULD clear EVERYTHING in the existing table should it not?
clear the table? no. youre assigning a new empty table to that variable and throwing the old one onto the lua garbage heap, it still exists in memory but it shouldnt be allocated to your variable any more.

how it's getting reassigned to your variable is weird, but its got to be in your code somewhere.

are you using any savedvaraible libraries? like acedb or similar? or is this from no library code?
  Reply With Quote
08-21-08, 10:25 PM   #8
Iriel
Super Moderator
WoWInterface Super Mod
Featured
Join Date: Jun 2005
Posts: 578
Your problem is almost certainly that you're doing all those operations BEFORE the saved variables are loaded, and the game then simply restores the old value of the table.
  Reply With Quote
08-22-08, 05:49 AM   #9
kerrang
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Oct 2006
Posts: 109
It's nothing to do with savedvariables - I've seen a similar issue in 2 addons and the table is only a 'savedvariable' in one of those addons so...

It's not behaviour before VARIABLES_LOADED either - this is something you can see after you've been playing for HOURS

Furthermore - 2 users have reported bugs which could ONLY be caused by a table not being completely emptied - so it's not just me The addon in question resets it's table VERY often - and yet we see 'weirdness' which goes away after a "/console reloadui" and the ONLY thing that would do is 'properly' clear the tables.

I think the issue is with tables WITHIN tables - and it may be down to my ignorance of how this should work of course.

It's not an easy bug to reproduce - there seems to be a specific set of circumstances (most likely related to being in/out of combat) but what I seem to be seeing is

fred['a'] = {}
fred ['a']['a'] = 1
fred ['a']['b'] = 1
fred ['a']['c'] = 1
fred = {}
fred['a'] = {}
fred ['a']['a'] = 1

At this point fred ['a']['b'] == 1

If, instead of using fred = {} I do something like

for v in pairs(fred) do
fred[v] = {}
end

I never see the issue - so that's what my addons do to clear tables right now. If I ever went to a 3rd level of 'nesting' I guess I'd have to reset both levels - and so on...
  Reply With Quote
08-22-08, 05:53 AM   #10
kerrang
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Oct 2006
Posts: 109
Originally Posted by arkayenro View Post
are you using any savedvaraible libraries? like acedb or similar? or is this from no library code?
No libraries whatsoever...
  Reply With Quote
08-22-08, 12:06 PM   #11
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
imho this is about weak tables and/or the garbage collection.

Please read http://www.lua.org/pil/17.html and http://www.lua.org/manual/5.1/manual.html#2.10.

[edit]
Could you please state which mod we're talking about?

Last edited by Duugu : 08-22-08 at 12:15 PM.
  Reply With Quote
08-25-08, 08:16 AM   #12
kerrang
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Oct 2006
Posts: 109
I saw this whilst developing both O.B.I. and O-Wheely! addons.

At one point I was creating and clearing tables quite frequently - however this being bad in terms of memory usage I've rewritten both addons NOT to do this now - so I don't have a working example...

A question, however...

If you write code which triggers on ON_UPDATE and takes a LONG time to run - can another ON_UPDATE event trigger before the first one is complete?

At one point I had some code scraping tooltips inefficiently and it was taking maybe .2sec to complete - which is a LONG time - could that code have been executed 'on top of itself'?
  Reply With Quote
08-25-08, 08:39 AM   #13
Akryn
A Firelord
AddOn Author - Click to view addons
Join Date: Mar 2008
Posts: 479
Originally Posted by kerrang View Post
If you write code which triggers on ON_UPDATE and takes a LONG time to run - can another ON_UPDATE event trigger before the first one is complete
No, the UI is single-threaded. As long as your OnUpdate code is running, no other UI code will run and no video frames will be drawn because the game waits for the UI to be ready before it draws each frame. If you create an infinite loop, for example, you'll completely freeze the game.
  Reply With Quote
08-25-08, 11:07 AM   #14
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
A while ago I made a simple mod to show this behavior.
http://www.scherbenweltkorps.de/systemtest.zip

The first slider controls a simple loop that is done on every OnUpdate:
Code:
	for x = 1, [slidervalue], 1 do
	end
The second slider creates a table if the slider's value changed:
Code:
	local value = getglobal("SystemTestMainSlider2"):GetValue()
	local size = table.getn(DummyTable)
	if size ~= value then
		DummyTable = {}
		local xt = _G.collectgarbage("count")
		for x = 1, value, 1 do
			table.insert(DummyTable, {"Test","Test","Test","Test","Test","Test","Test","Test","Test","Test","Test"})
		end
	end
	collectgarbage("collect")
It's a nice tool to lower your fps too. ;D

[edit]
This mod was originally to show that the client's performance isn't affected by the mod's memory usage but only by the mod's activity.

Last edited by Duugu : 08-25-08 at 11:20 AM.
  Reply With Quote
08-26-08, 02:29 PM   #15
kerrang
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Oct 2006
Posts: 109
Originally Posted by Duugu View Post
This mod was originally to show that the client's performance isn't affected by the mod's memory usage but only by the mod's activity.
That's quite interesting in itself...

With O.B.I., I'd got myself into a position where I had 2 mechanisms for updating ActionButtons.

One method was entirely event-based and used minimal CPU - but it reset (e.g. discarded) tables a LOT (hence he original issue here) and so it's memory usage was constantly climbing (until GC lowered it and it started again). This approach had some issues with the way some actionbar addons worked which were going to be hard to solve too.

The approach I've switched to now is more cpu intensive BUT it's very memory-efficient in that it uses no more memory once initially loaded. It also uses less CPU when you're in-combat which I think is where it matters most

What you're saying tho is that I've made my addon worse in performance terms??
  Reply With Quote
08-27-08, 06:10 AM   #16
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
Originally Posted by kerrang View Post
What you're saying tho is that I've made my addon worse in performance terms??
Nope, not really.

It's not about how much memory is used. It's about when or where the memory is allocated.

There are basically no performance losses due to high memory usage only. But there WILL be performance losses due to the memory allocating process itself (creating new tables) and there will be a noticeable "lag" on every garbage collection. (depending on how much memory is allocated)

So you could use a lot of memory. But never allocate new memory (create tables) within OnUpdate. (Sounds as you already discovered that. *g*)

The way you're doing it is the only practical way. (re-using tables instead of creating new tables).

Last edited by Duugu : 08-27-08 at 06:17 AM.
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Emptying a Table

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