Thread Tools Display Modes
01-09-24, 05:35 PM   #1
Benalish
A Flamescale Wyrmkin
 
Benalish's Avatar
Join Date: Dec 2012
Posts: 123
Stack overflow

May I ask why this code goes into stack overflow

Lua Code:
  1. local function SetWidgetScript(frame,method)
  2.     if frame:IsShown() then
  3.         for i = 1, #frame.buttons do
  4.             frame.buttons[i]:HookScript("OnMouseDown", method)
  5.         end
  6.     else
  7.         frame:SetScript(
  8.             "OnShow", --when "OnShow" is fired, IsShown() become true
  9.                 SetWidgetScript(frame,method)
  10.         )
  11.     end
  12. end

While it works fine by simply wrapping myfunc() inside the function environment after "OnShow"?

Lua Code:
  1. local function SetWidgetScript(frame,method)
  2.     if frame:IsShown() then
  3.         for i = 1, #frame.buttons do
  4.             frame.buttons[i]:HookScript("OnMouseDown", method)
  5.         end
  6.     else
  7.         frame:SetScript(
  8.             "OnShow", --when "OnShow" is fired, IsShown() become true
  9.             function()
  10.                 SetWidgetScript(frame,method)
  11.             end
  12.         )
  13.     end
  14. end

Last edited by Benalish : 01-09-24 at 05:42 PM.
  Reply With Quote
01-09-24, 07:34 PM   #2
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,326
The first example, you're calling yourself instead of registering a function to run as a script. What happens when you make a function call as an argument for another function is it runs the function call immediately and uses the return value(s) as the argument(s) for the second function. In this case, you're calling yourself (SetWidgetScript()) and :SetScript() is expecting to take any returns to use for the callback script. SetWidgetScript() doesn't actually return anything, so if it wasn't repeatedly calling itself, causing the stack overflow, it would end up sending nil to :SetScript().

The second example creates a dynamic function to call SetWidgetScript() with the arguments supplied as upvalues. Unlike the first example, you aren't calling it immediately as you are just giving it a function.



It's not exactly the way I'd design this function either way as trying to call it to register multiple callbacks on the same frame will cause the previous OnShow registrations to be lost. Also the OnShow script never unregisters itself, so it'll just keep calling itself whenever it gets fired, which will keep piling :HookScript() calls on top of each other.

Mouse scripts require a "visible" frame to fire, so there's no need to delay hooking until it's shown anyway.
__________________
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)

Last edited by SDPhantom : 01-09-24 at 07:52 PM.
  Reply With Quote
01-10-24, 07:29 AM   #3
Benalish
A Flamescale Wyrmkin
 
Benalish's Avatar
Join Date: Dec 2012
Posts: 123
The original code was

Lua Code:
  1. local function SetWidgetScript(frame,method)
  2.     if frame:IsShown() then
  3.         for i = 1, #frame.buttons do
  4.             frame.buttons[i]:HookScript("OnMouseDown", method)
  5.         end
  6.     else
  7.         frame:SetScript(
  8.             "OnShow", function()
  9.                  for i = 1, #frame.buttons do
  10.                      frame.buttons[i]:HookScript("OnMouseDown", method)
  11.                  end
  12.             end
  13.         )
  14.     end
  15. end

I changed the method in the "OnShow" script just to not repeat the for i=1...end part twice.
There is probably a better way to write a DRY script.
  Reply With Quote
01-11-24, 12:51 AM   #4
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,326
In all honestly, I rather use buttons than generic frames to receive clicks. As I said earlier, mouse events require the frame to be "visible" already to fire, they shouldn't if they're hidden. This is just over-engineered.

It should be this simple.
Lua Code:
  1. local function SetWidgetScript(frame,method)
  2.     for _,button in ipairs(frame.buttons) do
  3.         button:HookScript("OnMouseDown",method);
  4.     end
  5. 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 » Stack overflow


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