WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   function "has more then 60 upvalues" (https://www.wowinterface.com/forums/showthread.php?t=22340)

Azul 04-17-09 05:21 AM

function "has more then 60 upvalues"
 
It seems my OnUpdate function has to be pretty small or else the whole addon fails to load with the above error. How do I solve this (besides a horribly hackish (and slow) solution like making tons of frames with OnEvent functions)? Please help! :confused:

xConStruct 04-17-09 07:07 AM

Never encountered your message, but it seems like you're using a lot (over 60) of local variables which are then accessed by your OnUpdate-function which causes trouble.

As you create a lot of frames, you could try to store them in tables rather than locals - this would basically eliminate a lot of your upvalues as you're only accessing one in your function(the table).

In general, it would be more helpful to see some of your code or a description how you're creating/storing the frames. :)

Azul 04-17-09 07:20 AM

Quote:

Originally Posted by Cargor (Post 127898)
Never encountered your message, but it seems like you're using a lot (over 60) of local variables which are then accessed by your OnUpdate-function which causes trouble.

As you create a lot of frames, you could try to store them in tables rather than locals - this would basically eliminate a lot of your upvalues as you're only accessing one in your function(the table).

In general, it would be more helpful to see some of your code or a description how you're creating/storing the frames. :)

Thanks.

There is just one frame, for the OnUpdate function. It's a command based addon.

Also, arrays and globals are to slow and use to much meory.. and locals in the OnUpdate function lose all of their data on each frame.. so I need to know how to do it this way, with more then 60. Please help.


Here is some pseudo code;
Code:


local Var,AnotherVar,Foo,Bar,Etc=1,"blah blah blah",GetTime(),nil
local frame=CreateFrame("Frame")

frame:SetScript("OnUpdate",function(self)

some stuff that uses Var
some stuff that uses AnotherVar
some stuff that uses Foo
some stuff that doesn't use any of them
some stuff that uses Bar
some stuff that uses Etc

end)

SlashCmdList["somecmd"] = function (arg1)
        if Etc then
                Etc=nil
        else
                Etc=1
        end
end
SLASH_somecmd1="/justacmd"
SlashCmdList["anothercmd"] = function (arg1)
        AnotherVar=arg1
end
SLASH_anothercmd1="/justanothercmd"

In this little example there are 5 variables used. If I use a lot then I get the error and it won't run.

xConStruct 04-17-09 07:50 AM

You could try to split your OnUpdate-function into several smaller function which are called from the OnUpdate-function so that less upvalues are used in one single function.

Sorry if it doesn't help, but I'm just wondering why you need to do calculations with over 60 variables on every update. Maybe if you describe a bit what you want to achieve with the functions, we can come up with another solution.

Seems like a dilemma to me: accessing lots of upvalues without using tables/global environment while Lua can only handle up to 60.
Can't think of alternatives besides storing them somewhere else at the cost of speed or splitting up the function.

Azul 04-17-09 08:01 AM

Quote:

Originally Posted by Cargor (Post 127909)
You could try to split your OnUpdate-function into several smaller function which are called from the OnUpdate-function so that less upvalues are used in one single function.

Sorry if it doesn't help, but I'm just wondering why you need to do calculations with over 60 variables on every update. Maybe if you describe a bit what you want to achieve with the functions, we can come up with another solution.

Seems like a dilemma to me: accessing lots of upvalues without using tables/global environment while Lua can only handle up to 60.
Can't think of alternatives besides storing them somewhere else at the cost of speed or splitting up the function.

Thank you. I split them and the performance wasn't as bad as the other ways. :)


I still wish there was a way to fix the 60 upvalue limit though.

Nuckin 04-17-09 08:41 AM

Quote:

Originally Posted by Azul (Post 127913)
Thank you. I split them and the performance wasn't as bad as the other ways. :)


I still wish there was a way to fix the 60 upvalue limit though.

the 60-up error is there to try and keep you from eating up all the memory :)

And what splitting into functions does is it scopes parts of OnUpdate.
General info on scope: http://en.wikipedia.org/wiki/Variable_scoping

Azul 04-17-09 08:46 AM

Quote:

Originally Posted by Nuckin (Post 127928)
the 60-up error is there to try and keep you from eating up all the memory :)

And what splitting into functions does is it scopes parts of OnUpdate.
General info on scope: http://en.wikipedia.org/wiki/Variable_scoping

If I had malicious intentions couldn't I just eat all the memory with "var={} while 1 do table.tinsert(var,' ') end"? >_>

Azul 04-17-09 11:18 PM

What is wrong with this? It says that foo is global, and that it's nil.. when obviously it should be local (they all should), and not nil..

Code:

local frame=CreateFrame("Frame")
frame:SetScript("OnUpdate",function(self)
        if not foo then local foo,bar,text="foo","bar","" end
        text=foo..bar
end)


I'm really starting to hate lua with a passion. To bad there are no alternatives. :(

Sythalin 04-17-09 11:39 PM

Quote:

Originally Posted by Azul (Post 128147)
What is wrong with this? It says that bar is global, and that it's nil.. when obviously it should be local, and not nil..

Code:

local frame=CreateFrame("Frame")
frame:SetScript("OnUpdate",function(self)
        if not foo then
                local foo=1
                local bar="blah"
                local pi=3.14
                local text=""
        end
        text=foo..bar..pi
end)


I'm really starting to hate lua. I wish there was something else I could make addons in. :(

Since bar is declared locally in your IF statement, it won't be carried outside the block. Try putting it inside and see if it works.

Azul 04-17-09 11:41 PM

Quote:

Originally Posted by ChaosInc (Post 128149)
Since bar is declared locally in your IF statement, it won't be carried outside the block. Try putting it inside and see if it works.

Then I will lose the value of it on every frame.. not to mention the overhead will be nuts.

haste 04-17-09 11:59 PM

Quote:

Originally Posted by Azul (Post 128150)
Then I will lose the value of it on every frame.. not to mention the overhead will be nuts.

Premature optimization. Your design is obviously corrupted by this. You shouldn't really worry about the overhead in a OnUpdate from locals. Unless you create a bunch of tables on every OnUpdate, but then we're back to flawed design.

The overhead from locals is also far from nuts.

Sythalin 04-18-09 12:13 AM

Quote:

Originally Posted by Azul (Post 128147)
What is wrong with this? It says that foo is global, and that it's nil.. when obviously it should be local (they all should), and not nil..

Code:

local frame=CreateFrame("Frame")
frame:SetScript("OnUpdate",function(self)
        if not foo then local foo,bar,text="foo","bar","" end
        text=foo..bar
end)


I'm really starting to hate lua with a passion. To bad there are no alternatives. :(

Ok, no offense mate, but don't edit a different code into it when people are trying to help you figure out the original. I was confused there for a sec... :confused:

Try separating the function out to test functionality better:
Code:

local f = CreateFrame("Blah")
f:SetScript("OnUpdate", testfunction(self))

function testfunction(frame)
    if not foo then
        local foo = "foo"
        local bar = "bar"
    end
    text=foo..bar
    DEFAULT_CHAT_FRAME:AddMessage(text)  -- test to make sure everything goes smoothly
end

Also note that I removed local text = "" as you don't need it. It's already going to be overridden each time without having to manually clear it. After you get it working how you want, then go back and optimize the code (as haste pointed out).

Azul 04-18-09 12:15 AM

Quote:

Originally Posted by haste (Post 128155)
Premature optimization. Your design is obviously corrupted by this. You shouldn't really worry about the overhead in a OnUpdate from locals. Unless you create a bunch of tables on every OnUpdate, but then we're back to flawed design.

The overhead from locals is also far from nuts.

No.


Quote:

Originally Posted by ChaosInc (Post 128158)
Ok, no offense mate, but don't edit a different code into it when people are trying to help you figure out the original. I was confused there for a sec... :confused:

Try separating the function out to test functionality better:
Code:

local f = CreateFrame("Blah")
f:SetScript("OnUpdate", testfunction(self))

function testfunction(frame)
    if not foo then
        local foo,bar="foo","bar"
    end
    text=foo..bar
    DEFAULT_CHAT_FRAME:AddMessage(text)  -- test to make sure everything goes smoothly
end

Also note that I removed local text = "" as you don't need it. It's already going to be overridden each time without having to manually clear it. After you get it working how you want, then go back and optimize the code (as haste pointed out).

Was just simplifying the example to make it easier to understand, and hadn't seen your reply yet.

Yes text is supposed to be overwritten in the example.. and it's supposed to be a local.


BTW your example is broken.

Even after fixing the CreateFrame, it says "attempt to call function 'testfunction', a nil value" and I don't know how to fix that, since it's defined right there clear as day. :s


Edit: fixed it by moving it over the OnUpdate.. and now it says it's trying to concatenate foo as a GLOBAL, and that it's NIL. Just like in my example. :(

celebros 04-18-09 12:16 AM

At first blush this looks like a scope issue.
http://www.lua.org/manual/5.1/manual.html#2.6

I'm a bit curious of the need for 60 separate local variables being accessed on each frame update. You also should take care of creating new locals in each update as well, as it appears that your goal is extreme performance. Though I would offer the advice that getting it working with a table at first and then going back and optimizing the most often executed code wouldntield better or at least more timely results. Just my $.02. I could be wrong.

Sythalin 04-18-09 12:22 AM

Sorry, wasn't meant to be a full blown working example, just kind of a guide to help ya debug. It's 1:30am and I'm tired. :p

Azul 04-18-09 12:25 AM

Quote:

Originally Posted by celebros (Post 128161)
At first blush this looks like a scope issue.
http://www.lua.org/manual/5.1/manual.html#2.6

I'm a bit curious of the need for 60 separate local variables being accessed on each frame update. You also should take care of creating new locals in each update as well, as it appears that your goal is extreme performance. Though I would offer the advice that getting it working with a table at first and then going back and optimizing the most often executed code wouldntield better or at least more timely results. Just my $.02. I could be wrong.

They are generated once on load. This process is very expensive, and can't really be optimized any more then it already is. Their values are (sometimes) modified outside of the OnUpdate by slash commands. Performance is to slow when they are global. When there are over 60 defined local above the OnUpdate function I get that stupid "to many upvalues" error.

Guess I should have explained this in the first post. I thought I did though. Sorry.

P.S. It does work as tables but is to slow.


Quote:

Originally Posted by ChaosInc (Post 128164)
Sorry, wasn't meant to be a full blown working example, just kind of a guide to help ya debug. It's 1:30am and I'm tired. :p

Thanks, it has the exact same problem my example does, though.

Sythalin 04-18-09 12:32 AM

Quote:

Originally Posted by Azul (Post 128160)
Edit: fixed it by moving it over the OnUpdate.. and now it says it's trying to concatenate foo as a GLOBAL, and that it's NIL. Just like in my example. :(

Oh duh, it's a logic issue. Ok,here's the lowdown on what's happening in your example (still tired, bear with me :D).

1) check for global foo
Code:

if not foo then...
2) if global foo doesn't exist, create a local foo
Code:

local foo = "foo"
3) after declaring the end of the if statement, local foo is destroyed. Translated as per the compiler:
Code:

foo = NIL
4) attempt to create text
Code:

text = foo..bar
5) ERROR - a global foo still hasn't been created. And since the local was destroyed in stage 3, foo still remains as NIL

Also, I realize after looking back that the function would have to go before the scripts (which is always a good practice to maintain, for the record), but you posted the fix already.

Azul 04-18-09 12:35 AM

Quote:

Originally Posted by ChaosInc (Post 128172)
Oh duh, it's a logic issue. Ok,here's the lowdown on what's happening in your example (still tired, bear with me :D).

1) check for global foo
Code:

if not foo then...
2) if global foo doesn't exist, create a local foo
Code:

local foo = "foo"
3) after declaring the end of the if statement, local foo is destroyed. Translated as per the compiler:
Code:

foo = NIL
4) attempt to create text
Code:

text = foo..bar
5) ERROR - a global foo still hasn't been created. And since the local was destroyed in stage 3, foo still remains as NIL

Also, I realize after looking back that the function would have to go before the scripts (which is always a good practice to maintain, for the record), but you posted the fix already.

How do I check for a local foo instead? And be defined in the function scope instead of the if statement? If this is impossible then defining them inside the update definitely isn't an alternative and I need a way around the 60 upvalue limit like I asked for in the first post. :(

Sythalin 04-18-09 12:42 AM

You can't check for a local variable outside it's block. You'd have to rename the global foo as something else and pass the data out to it.

Code:

function testfunction(frame)
    if not arg1 then
        local foo = "foo"
        local bar = "bar"
        arg1 = foo
        arg2 = bar
    end
    text=arg1.. arg2
    DEFAULT_CHAT_FRAME:AddMessage(text)  -- test to make sure everything goes smoothly

local f = CreateFrame("FRAME", "Blah")
f:SetScript("OnUpdate", testfunction(self))

end

But that won't help your 60 upvalue any. For that, you're don't really have a choice but to condense it down via one of the previously mentioned methods.

Azul 04-18-09 12:47 AM

Quote:

Originally Posted by ChaosInc (Post 128175)
You can't check for a local variable outside it's block. You'd have to rename the global foo as something else and pass the data out to it.

Code:

function testfunction(frame)
    if not arg1 then
        local foo = "foo"
        local bar = "bar"
        arg1 = foo
        arg2 = bar
    end
    text=arg1.. arg2
    DEFAULT_CHAT_FRAME:AddMessage(text)  -- test to make sure everything goes smoothly

local f = CreateFrame("FRAME, "Blah")
f:SetScript("OnUpdate", testfunction(self))

end

But that won't help your 60 upvalue any. For that, you're don't really have a choice but to condense it down via one of the previously mentioned methods.

Tables are to slow. If there's a decent (not function call, like the extremely slow bit library) way to do bitwise operations in it, I think I could bring the variable count down enough to placate this arbitrary limitation. I don't know how though. All I could find was that uselessly slow bit function library. Any ideas?

If not, then all I can think of is updating the lua package in WoW to one that works better.. I don't know how to do this though, and it might be frowned upon by Blizzard (can anyone confirm this?).


All times are GMT -6. The time now is 07:09 AM.

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