squirrel
squirrel copied to clipboard
base is null in a method called with bindenv via a corountine?
The smallest script I could make to repro the issue is this one:
class TestBase
{
function PlaySoundEffect(sfx)
{
print("PlaySoundEffect:" + sfx);
}
}
class Test extends TestBase
{
mData = {};
mThread = "";
mFirst = true;
function constructor()
{
mThread = ::newthread(CoRoutineProc);
print("Base is: " + base); // BASE IS OK Base is: (class : 0x0x50eb48)
base.PlaySoundEffect("Test1");
}
function Update()
{
if (mFirst)
{
mThread.call(this);
mFirst = false;
}
else
{
mThread.wakeup(this);
}
}
function CoRoutineProc(thisPtr)
{
thisPtr.Exec.bindenv(thisPtr)();
}
function Exec()
{
mData = { mFunc = Test.TestFunction};
while (true)
{
mData.mFunc.bindenv(this)();
::suspend();
}
}
function TestFunction()
{
DoACallBack("test",
{
onFrame = function()
{
print("Base is: " + base); // WHY IS BASE NULL HERE?? Base is: (null : 0x(nil))
base.PlaySoundEffect("Test2");
}
});
}
function DoACallBack(name, params = null)
{
if ("onFrame" in params)
{
print("Calling nested call back");
if (params.onFrame.bindenv(this)())
{
}
}
::suspend();
}
}
local t = Test();
t.Update();
In TestFunction when onFrame is called base is null, is this an issue with my script or could it be a bug?
"base" is only set to a closure when the closure is added to a class, either by declaring it in the body or by adding it with the <- operator( as in Myclass.funcname <- function() {}). It is not a free variable.
Hmm this seems a little quirky - if I add mBase = base; to the class and replace all use of base. with mBase. then I get to access "base". Your suggestion won't work in my example because it seems that <- can't be used after the class is constructed or on an instance of a class?
I would have thought the pattern of
someclass::function()
{
this.callMeWhenSomethingHappens(function() { print("It happened"); });
}
Would be quite common in scripting. Or is something like mBase = base the usual workaround for this situation?