WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Function questions (https://www.wowinterface.com/forums/showthread.php?t=46185)

Resike 04-06-13 05:09 AM

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?

Vlad 04-06-13 06:21 AM

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.

ravagernl 04-06-13 06:57 AM

Quote:

Originally Posted by Resike (Post 275870)
[...]
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

Resike 04-06-13 07:36 AM

Quote:

Originally Posted by ravagernl (Post 275883)
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)


Ailae 04-06-13 09:48 AM

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)

Resike 04-06-13 09:58 AM

Quote:

Originally Posted by Ailae (Post 275888)
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.

Vlad 04-06-13 10:50 AM

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.

Resike 04-06-13 10:59 AM

Quote:

Originally Posted by Vlad (Post 275890)
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.

Nibelheim 04-06-13 11:12 AM

Quote:

Originally Posted by Resike (Post 275891)
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.

Vlad 04-06-13 02:45 PM

You would replace the "self" (the "t" object reference) with what ever argument you pass in the function as you run it.

Phanx 04-06-13 06:33 PM

Quote:

Originally Posted by Resike (Post 275891)
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


Resike 04-07-13 05:32 AM

Quote:

Originally Posted by Phanx (Post 275924)
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.

Quote:

Originally Posted by Phanx (Post 275924)
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.

Quote:

Originally Posted by Phanx (Post 275924)
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?

Sharparam 04-07-13 05:47 AM

On a slightly unrelated note, the following:
Quote:

Originally Posted by Resike (Post 275941)
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".

Resike 04-07-13 07:37 AM

Quote:

Originally Posted by F16Gaming (Post 275943)
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


Sharparam 04-07-13 07:38 AM

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

Resike 04-07-13 09:43 AM

Quote:

Originally Posted by F16Gaming (Post 275948)
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

Sharparam 04-07-13 10:29 AM

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.

Seerah 04-07-13 03:03 PM

Code smarter, not harder.

Nibelheim 04-07-13 03:15 PM

Quote:

Originally Posted by Seerah (Post 275989)
Code smarter, not harder.

+1 (though I lack the smarts of a leet coder so I usually have to code hard :p)

We must code smarter, not harder. Faster, not smarter. And forever looping, looping, LOOPING towards freedom!

SDPhantom 04-08-13 12:44 PM

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);



All times are GMT -6. The time now is 01:57 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI