Thread Tools Display Modes
04-06-13, 05:09 AM   #1
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Function questions

So i have a function like that:

Code:
function PVPSound_UpdateSoundEffectEngine(self, elapsed)

end

PVPSoundEffectSoundEngineFrame:SetScript("OnUpdate", PVPSound_UpdateSoundEffectEngine)
If i change the function to:

local addon, ns = ...
local PVPSound = { }
ns.PVPSound = PVPSound

Code:
function PVPSound:UpdateSoundEffectEngine(self, elapsed)

end

PVPSoundEffectSoundEngineFrame:SetScript("OnUpdate", PVPSound:UpdateSoundEffectEngine)
Then why cant i make the function local?
Also why cant call the function like that with the SetScript?
  Reply With Quote
04-06-13, 06:21 AM   #2
Vlad
A Molten Giant
 
Vlad's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 793
Just some code, maybe it helps:
Code:
local test = {} -- local example table
function test:Hello(word) print(word) end -- same as below
function test.Hello(self, word) print(word) end -- same as above
test:Hello("World") -- same as below
test.Hello(test, "World") -- same as above
These are all local because "test" is a local table.

If you want a local function you do local function onupdate(self, elapsed) ... end and now you can SetScript directly to "onupdate", and it is a local function.

The benefit of keeping everything to your "ns" for example is that all the files can access those functions trough the namespace.
__________________
Profile: Curse | Wowhead
  Reply With Quote
04-06-13, 06:57 AM   #3
ravagernl
Proceritate Corporis
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2006
Posts: 1,176
Originally Posted by Resike View Post
[...]
Then why cant i make the function local?
Also why cant call the function like that with the SetScript?
Because your syntax is wrong. You can not set a script handler using the syntactic colon operator. SetScript/HookScript expect a reference to a function. Using the colon is just a shorter way of passing the table as the first argument:
lua Code:
  1. local someaddon = {a = 10, plus = function(self) self.a = self.a + 5 end}
  2. someaddon:plus(5)
  3. print(someaddon.a) -- prints 15
  4.  
  5. local addonb = {a = 30, plus = someaddon.plus}
  6. addonb:plus(10)
  7. print(addonb.a) -- prints 40
  8.  
  9. someaddon.plus(addonb, 5)
  10. print(someaddon.a) -- prints 20
  11. print(addonb.a) -- prints 40
  Reply With Quote
04-06-13, 07:36 AM   #4
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by ravagernl View Post
Because your syntax is wrong. You can not set a script handler using the syntactic colon operator. SetScript/HookScript expect a reference to a function. Using the colon is just a shorter way of passing the table as the first argument:
lua Code:
  1. local someaddon = {a = 10, plus = function(self) self.a = self.a + 5 end}
  2. someaddon:plus(5)
  3. print(someaddon.a) -- prints 15
  4.  
  5. local addonb = {a = 30, plus = someaddon.plus}
  6. addonb:plus(10)
  7. print(addonb.a) -- prints 40
  8.  
  9. someaddon.plus(addonb, 5)
  10. print(someaddon.a) -- prints 20
  11. print(addonb.a) -- prints 40
And if i do it like that?

Code:
local function OnUpdate(self, elapded)
    PVPSound:UpdateSoundEffectEngine(self, elapsed)
end

function PVPSound:UpdateSoundEffectEngine(self, elapsed)

end

PVPSoundEffectSoundEngineFrame:SetScript("OnUpdate", OnUpdate)
  Reply With Quote
04-06-13, 09:48 AM   #5
Ailae
A Rage Talon Dragon Guard
 
Ailae's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2007
Posts: 318
I guess you could, but why would you?

You're creating a function just to call another function that does all the stuff (I presume). As long as your PVPSound table is local, the UpdateSoundEffectEngine function will also be local and you can set it as the script handler.

Lua Code:
  1. function PVPSound:UpdateSoundEffectEngine(elapsed)
  2. -- stuff goes on here
  3. end
  4.  
  5. PVPSoundEffectSoundEngineFrame:SetScript("OnUpdate", PVPSound.UpdateSoundEffectEngine)
__________________
Oh, the simulated horror!
  Reply With Quote
04-06-13, 09:58 AM   #6
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Ailae View Post
I guess you could, but why would you?

You're creating a function just to call another function that does all the stuff (I presume). As long as your PVPSound table is local, the UpdateSoundEffectEngine function will also be local and you can set it as the script handler.

Lua Code:
  1. function PVPSound:UpdateSoundEffectEngine(elapsed)
  2. -- stuff goes on here
  3. end
  4.  
  5. PVPSoundEffectSoundEngineFrame:SetScript("OnUpdate", PVPSound.UpdateSoundEffectEngine)
Oh i see you can call it with "PVPSound.UpdateSoundEffectEngine" have no clue why did i wanted to call it with "PVPSound:UpdateSoundEffectEngine".

Well the PVPSound table is a local, but its a namespace shared local between my addon's files.
  Reply With Quote
04-06-13, 10:50 AM   #7
Vlad
A Molten Giant
 
Vlad's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 793
Just keep in mind that the word "self" is what ever caller calls the function.

For example:
Code:
local t = {a = 5}
function t:test(a, b, ...) print(self, a, b, ...) end -- simply prints the arguments (joined by space)
t:test("A", "B") -- prints "<object 't'> A B"
t.test("A", "B") -- prints "A B nil"
You see that using ":" suddenly takes the left object of the ":" and passes that, making the "self" in the function refer to it, or if you use a "." then you have to supply what value "self" is assigned.

Also declaring a function, it's important to remember that:
Code:
function t:test() print(self) end -- "self" is the object "t"

function t.test(self) print(self) end -- "self" is what ever you pass into the function (BEWARE, this and the one above are the same! just different way to write them, also this way you can call "self" anything, for instance it could be "kek" and still refer to the proper object.)

function t.test() print(self) end -- "self" is nil
Now getting to my point, if you use something like:
Code:
frame:SetScript("OnUpdate", t.test)
"t.test" is the function, but the "self" you use in that function will in this case reference "frame" and not "t" so keep that in mind if stuff don't work the way you expect!

For instance your function ns:OnUpdate(elapsed) end if you frame:SetScript("OnUpdate", ns.OnUpdate) then when the function is called the "self" object will refer to "frame" and not "ns", so if you try to for instance call another function you should use ns:OtherFunc() and not self:OtherFunc() like you might expect.

Sorry for messy post.
__________________
Profile: Curse | Wowhead
  Reply With Quote
04-06-13, 10:59 AM   #8
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Vlad View Post
Just keep in mind that the word "self" is what ever caller calls the function.

For example:
Code:
local t = {a = 5}
function t:test(a, b, ...) print(self, a, b, ...) end -- simply prints the arguments (joined by space)
t:test("A", "B") -- prints "<object 't'> A B"
t.test("A", "B") -- prints "A B nil"
You see that using ":" suddenly takes the left object of the ":" and passes that, making the "self" in the function refer to it, or if you use a "." then you have to supply what value "self" is assigned.

Also declaring a function, it's important to remember that:
Code:
function t:test() print(self) end -- "self" is the object "t"

function t.test(self) print(self) end -- "self" is what ever you pass into the function (BEWARE, this and the one above are the same! just different way to write them, also this way you can call "self" anything, for instance it could be "kek" and still refer to the proper object.)

function t.test() print(self) end -- "self" is nil
Now getting to my point, if you use something like:
Code:
frame:SetScript("OnUpdate", t.test)
"t.test" is the function, but the "self" you use in that function will in this case reference "frame" and not "t" so keep that in mind if stuff don't work the way you expect!

For instance your function ns:OnUpdate(elapsed) end if you frame:SetScript("OnUpdate", ns.OnUpdate) then when the function is called the "self" object will refer to "frame" and not "ns", so if you try to for instance call another function you should use ns:OtherFunc() and not self:OtherFunc() like you might expect.

Sorry for messy post.
And which self i'm gonna get if i use it like that?

Code:
function t:test(self)
    print(self)
end
Honestly i don't need the "PVPSound" table for nothing, just to bypass local functions between files.
  Reply With Quote
04-06-13, 11:12 AM   #9
Nibelheim
local roygbi-
 
Nibelheim's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 1,600
Originally Posted by Resike View Post
And which self i'm gonna get if i use it like that?

Code:
function t:test(self)
    print(self)
end
You'll get the self in brackets.
  Reply With Quote
04-06-13, 02:45 PM   #10
Vlad
A Molten Giant
 
Vlad's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 793
You would replace the "self" (the "t" object reference) with what ever argument you pass in the function as you run it.
__________________
Profile: Curse | Wowhead
  Reply With Quote
04-06-13, 06:33 PM   #11
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Resike View Post
Honestly i don't need the "PVPSound" table for nothing, just to bypass local functions between files.
Just use dot notation instead of colon notation to avoid confusion:

Code:
local _, ns = ...

function ns.FancyPrint(caller, ...)
   print("MyAddon:", ...)
end

local frame = CreateFrame("Frame")
frame:RegisterEvent("UNIT_AURA")
frame:SetScript("OnEvent", ns.FancyPrint)
-- will print, for example, "MyAddon: UNIT_AURA player")
Other file:
Code:
local _, ns = ...
ns.FancyPrint(nil, "Hello world!")
-- will print ("MyAddon: Hello world!")
The (probably more sensible) alternative would be to define script handlers directly in the SetScript call:

Code:
PVPSoundEffectSoundEngineFrame:SetScript("OnUpdate", function(self, elapsed)
     -- stuff goes on here
end)
The only reason to define the script handler function separately would be if you planned to call the same function from other places, or you wanted multiple frames to use the same event handler function, etc.

Also, when you set a list of variables with the same name, when you're done, there is only one copy of the variable, and it contains the last value set:

Code:
local var, var, var, var = 1, 2, "cat", "dog"
print(var) -> "dog"
So:

Code:
function object:method(self)
    print(self)
end
object:method("lolcats") -> "lolcats"
... because it's equivalent to:

Code:
function objec*****thod(self, self)
    print(self)
end
__________________
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.

Last edited by Phanx : 04-06-13 at 06:35 PM.
  Reply With Quote
04-07-13, 05:32 AM   #12
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Phanx View Post
Just use dot notation instead of colon notation to avoid confusion:
I saw other addons use the : notation so thats why i choose this one too.

Originally Posted by Phanx View Post
The (probably more sensible) alternative would be to define script handlers directly in the SetScript call:

Code:
PVPSoundEffectSoundEngineFrame:SetScript("OnUpdate", function(self, elapsed)
     -- stuff goes on here
end)
The only reason to define the script handler function separately would be if you planned to call the same function from other places, or you wanted multiple frames to use the same event handler function, etc.
My current onupdate handler looks like this now:

Code:
local PVPSoundEffectSoundEngineFrame = CreateFrame("Frame", "PVPSoundEffectSoundEngineFrame")
local TimeSinceLastEffectUpdate = 0

function PVPSound:UpdateSoundEffectEngine(elapsed)
	if PS_EnableAddon == true then
		if PS_SoundEffect == true then
			TimeSinceLastEffectUpdate = TimeSinceLastEffectUpdate + elapsed
			while TimeSinceLastEffectUpdate > PVPSound_NextEffectUpdate do
				TimeSinceLastEffectUpdate = TimeSinceLastEffectUpdate - PVPSound_NextEffectUpdate
				PVPSound_NextEffectUpdate = PVPSound:PlayNextSoundEffect()
			end
		end
	end
end

PVPSoundEffectSoundEngineFrame:SetScript("OnUpdate", PVPSound.UpdateSoundEffectEngine)
But i have like 10 of em in my addon, and i might want to mergre them later.

Originally Posted by Phanx View Post
Also, when you set a list of variables with the same name, when you're done, there is only one copy of the variable, and it contains the last value set:

Code:
local var, var, var, var = 1, 2, "cat", "dog"
print(var) -> "dog"
So:

Code:
function object:method(self)
    print(self)
end
object:method("lolcats") -> "lolcats"
I see but since it only overwrites nearly nothing in my case, then i should be fine or not?
  Reply With Quote
04-07-13, 05:47 AM   #13
Sharparam
A Flamescale Wyrmkin
 
Sharparam's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2011
Posts: 102
On a slightly unrelated note, the following:
Originally Posted by Resike View Post
Code:
if PS_EnableAddon == true then
		if PS_SoundEffect == true then
Can be simplified to:
Code:
if PS_EnableAddon and PS_SoundEffect then
There's no need to have a separate if-clause for every boolean, and booleans can be tested without "== true".
  Reply With Quote
04-07-13, 07:37 AM   #14
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by F16Gaming View Post
On a slightly unrelated note, the following:


Can be simplified to:
Code:
if PS_EnableAddon and PS_SoundEffect then
There's no need to have a separate if-clause for every boolean, and booleans can be tested without "== true".
Yeah, i know i just recently edited that line, thats why the double if, but if i dont put == true, then it gonna run even if it has different values like "icecream" or "lolwhatever", and i only want it to run when its really true.

Code:
if something then
    --
end
Is equivalent with :


Code:
if something ~= nil and something ~= false then
    --
end

Last edited by Resike : 04-07-13 at 09:43 AM.
  Reply With Quote
04-07-13, 07:38 AM   #15
Sharparam
A Flamescale Wyrmkin
 
Sharparam's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2011
Posts: 102
Why would PS_EnableAddon ever have a string value, when it only ever gets set to true/false? But each to their own I guess :P
  Reply With Quote
04-07-13, 09:43 AM   #16
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by F16Gaming View Post
Why would PS_EnableAddon ever have a string value, when it only ever gets set to true/false? But each to their own I guess :P
It's a global someone can taint it with their addon! :P
  Reply With Quote
04-07-13, 10:29 AM   #17
Sharparam
A Flamescale Wyrmkin
 
Sharparam's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2011
Posts: 102
If it's a global, then the "PS_" prefix seems a bit short to identify an addon. There is probably quite a few with the "PS" initials. Perhaps use the full addon name for the global prefix, to avoid collisions with other addons.
  Reply With Quote
04-07-13, 03:03 PM   #18
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Code smarter, not harder.
__________________
"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
04-07-13, 03:15 PM   #19
Nibelheim
local roygbi-
 
Nibelheim's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 1,600
Originally Posted by Seerah View Post
Code smarter, not harder.
+1 (though I lack the smarts of a leet coder so I usually have to code hard )

We must code smarter, not harder. Faster, not smarter. And forever looping, looping, LOOPING towards freedom!
  Reply With Quote
04-08-13, 12:44 PM   #20
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
Does your handler really need to be run outside of the frame triggering it by OnUpdate? If not, it may be easier to use a different syntax.

For example, this method of defining a function also works.
Code:
Func = function(args)
-- Do stuff
end


Using that method, you can dynamically create a function just for the frame's OnUpdate handler.
Code:
Frame:SetScript("OnUpdate",function(self,elapsed)
-- Do stuff
end);
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Function questions

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