Thread Tools Display Modes
08-31-10, 07:07 PM   #1
TLH
A Murloc Raider
AddOn Author - Click to view addons
Join Date: Aug 2010
Posts: 8
[Lua] Coroutines and Class/Namespace functions

So this isn't a large problem, the end result being less clutter in the form of globals, but would be nice to clean up my addon as much as possible before uploading it to somewhere reputable. Like Wowinterface! Hi btw

The problem appears when I simply change the functions that are used for coroutines from being global to being part of a namespace/class/whatever you call Lua's mimicry of it. The difference in question is something like the difference between these:

Code:
Foo = function(n) return 2*n end
co = coroutine.create(Foo)
Code:
Bar={};
Bar.Foo = function(n) return 2*n end
co = coroutine.create(Bar.Foo)
Is there anything to know about coroutines that could explain differences in their behaviour during coroutine.resume just because the function fed to coroutine.create is part of a table/namespace (e.g. Bar.Foo) as opposed to a global (e.g. Foo)?

Thanks!
  Reply With Quote
08-31-10, 07:51 PM   #2
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
I thought the coroutines stuff wasn't included in WoW's Lua engine?
__________________
"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
08-31-10, 08:06 PM   #3
Motig
A Fallenroot Satyr
 
Motig's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2010
Posts: 23
Originally Posted by Seerah View Post
I thought the coroutines stuff wasn't included in WoW's Lua engine?
That's what I read too when I was looking for info about it.
  Reply With Quote
08-31-10, 08:25 PM   #4
Tuller
A Warpwood Thunder Caller
 
Tuller's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 91
Coroutines were added in 2.0.1:
http://www.wowwiki.com/Patch_2.0.1/API_changes
  Reply With Quote
08-31-10, 10:21 PM   #5
Sythalin
Curse staff
 
Sythalin's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 680
They were added, but not recommended as they eat memory for breakfast. I haven't checked the link but I recall them saying something about that when it was released.
  Reply With Quote
09-01-10, 03:49 AM   #6
TLH
A Murloc Raider
AddOn Author - Click to view addons
Join Date: Aug 2010
Posts: 8
Yus, they're present and they work fine (that is, until I create them from namespace functions instead of global functions).

I understand the memory thing, though the alternative is to add a bunch of code and set up my own variables to save the state of the operations; basically mimicing a coroutine thread anyway.

And yeah, I'll not worry about it too much; it was just something I picked up on while going through the code, making things local where possible (saves memory!) and putting as many globals as I can into a namespace.
  Reply With Quote
09-01-10, 10:42 AM   #7
Vrul
A Scalebane Royal Guard
 
Vrul's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2007
Posts: 404
Originally Posted by TLH View Post
Yus, they're present and they work fine (that is, until I create them from namespace functions instead of global functions).
Can you give an example where this occurs (not just saying its "like" something)?
  Reply With Quote
09-01-10, 01:31 PM   #8
TLH
A Murloc Raider
AddOn Author - Click to view addons
Join Date: Aug 2010
Posts: 8
Originally Posted by Vrul View Post
Can you give an example where this occurs (not just saying its "like" something)?

Yus, that I can! Example is below.

I also think I've found and corrected the 'problem', though I still don't quite understand what goes wrong. It seems to be in the syntax of declaring the function. In Wowwiki's page on Object-oriented programming, they use syntax such as:

Code:
function Character:new()
	-- code
end
This 'appears' to work fine until coroutines are involved, where the declaration 'seems' to need to be:

Code:
Character.new = function()
	-- code
end

I've made a quick mockup scenario to illustrate it here. All this program actually does is multiply two numbers together using the worst method possible, but it makes a good example
To try it with the fail-syntax, comment out line 8 and remove the comment from line 5.

Code:
-- Make a namespace
test={};

-- This syntax fails
--function test:Multiply(a, b)

-- This syntax succeeds
test.Multiply = function(a, b)
	local ans=0;
	
	while b>0 do
		ans = ans+a;
		b = b-1;

		-- Drop out here so as to run the While only once per Resume
		coroutine.yield();
	end
	
	return ans;
end


-- Create the thread
test.co = coroutine.create(test.Multiply);

-- This function would be called over time, e.g. with OnUpdate
test.Run = function()
	local flag, out;
	
	-- Multiply 3 by 5.
	flag, out = coroutine.resume(test.co, 3, 5);
	
	if out==nil then
		-- Not yet complete
		print("Iteration");
	else
		-- Complete
		print(out);
	end
end


-- Simulate multiple calls to Run
for i=1,6 do
	test.Run();
end
*

Declaring the function with 'function test:Multiply(a, b)' gives output:
Code:
11: attempt to compare number with nil
cannot resume dead coroutine
cannot resume dead coroutine
cannot resume dead coroutine
cannot resume dead coroutine
cannot resume dead coroutine
Declaring the function with 'test.Multiply = function(a, b)' gives output:
Code:
Iteration
Iteration
Iteration
Iteration
Iteration
15
*

Line 11 is the one containing 'b>0', so I guess test.Multiply isn't receiving its arguments for some reason. The only difference there is the line containing 'function', and there lies the mysterious part ^^

Last edited by TLH : 09-01-10 at 01:35 PM.
  Reply With Quote
09-01-10, 01:46 PM   #9
xConStruct
A Chromatic Dragonspawn
 
xConStruct's Avatar
AddOn Author - Click to view addons
Join Date: May 2008
Posts: 199
Code:
function test:Multiply(a, b)
is actually short-hand for
Code:
function test.Multiply(self, a, b)
So, your two numbers get stored in 'self' and 'a' this way, making b = nil.

Try if this works, passing 'self'/'test' along:
Code:
flag, out = coroutine.resume(test.co, test, 3, 5);
__________________
« Website | GitHub »

Oh hai!
  Reply With Quote
09-01-10, 02:20 PM   #10
TLH
A Murloc Raider
AddOn Author - Click to view addons
Join Date: Aug 2010
Posts: 8
Ah yus! That accounts for the difference entirely, so I'll set anything that doesn't need class-style behaviour to the namespace-style notation.

Thanks again :3
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » [Lua] Coroutines and Class/Namespace functions


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