I have just tracked down a "problem" with timeoutObjects, and
probably also MIAWs.
<CEO summary>
Always assign the result of the timeout() function to a variable,
when creating a new timeoutObject.
</CEO summary>
Everything is dandy, if you do like so:
localDummy = timeOut(me.string).new(0, #dummy , me)
Then the timeoutObject will be "cleared" (or "destroyed" or garbage
collected) when the last reference to the timeoutObject is removed,
which occurs when "forget" is issued on the timeoutObject, provided
that no references to the timeoutObject persist anywhere.
As with any other "object" in Lingo, this means that the
property-stack of the object is cleared, and consequently that the
refCount of any object stored in a property of the object, will drop
by one, potentially leading to a cascading destruction of objects.
In the case of timeoutObjects, it is obviously primarily the refcount
of the targetObject, that we want to drop, particularly when the
timeoutObject holds the one and only reference to the targetObject,
and we rely on the destruction of the timeoutObject, to also destroy
the targetObject.
If however, you don't "catch" the returned timeoutObject-reference
from the timeout() function, like so:
timeOut(me.string).new(0, #dummy , me)
Then the "destruction mechanism" fails, when the timeoutObject is
later "dereferenced", causing a "leaked" reference to the
targetObject to persist (, and probably also a leaked reference to
the timeoutObject itself).
This phenomena has lead to a lot of confusion, in recent discussions,
and spawned the work-around, of explicitly clearing the targetObject
of a timeoutObject before forgetting the timeoutObject.
While this would indeed lead to the desired result, that the
targetObject would subsequently become garbage-collected, there is no
knowing the consequences of potentially, having lots of "leaked"
timeoutObjects dangling around in RAM.
Some have also reported about mutual references as the cause, in
scenarios, where there were no such mutual references.
The "bare-bones test" looks like this:
on beginSprite me
put
put #beginSprite_1, me
----
t = timeOut("test").new(0, #dummy, me)
t = VOID
put #beginSprite_2, me
timeOut("test").forget()
put #beginSprite_3, me
----
timeOut("test").new(0, #dummy, me)
put #beginSprite_4, me
timeOut("test").forget()
put #beginSprite_5, me
----
put
end
-- Welcome to Director --
--
-- #beginSprite_1 <offspring "" 4 7577610>
-- #beginSprite_2 <offspring "" 5 7577610>
-- #beginSprite_3 <offspring "" 4 7577610>
-- #beginSprite_4 <offspring "" 5 7577610>
-- #beginSprite_5 <offspring "" 5 7577610>
--
The output is not "polished", but the point is that in the first
case, the refCount drops when the timeoutObject is forgotten, but in
the second case, the refCount remains, showing, that a leaked
reference still points to the testObject.
**************************
This "problem" (you can also try to spell "problem" with only three
letters... ;-)
caused some code, I designed for closing MIAWs, to malfunction.
Below is a new variation of that code, which is corrected for the
aforementioned problem, but also redesigned due to my recent
discovery of the actual meaning of "forget", namely that "forget" in
itself does *not* destroy an object.
Apparently this new code works fine, but given the recent
experiences, it should probably undergo some field-testing, before it
is evangelized.
--------<movie script>--------
on closeWindow
script("miawCloserClass").new(the activeWindow)
end
--------</movie script>--------
--------<parent script "miawCloserClass">--------
--miawCloserClass
property pWindow
on new me, aWindow
pWindow = aWindow
pWindow.forget()
tell the stage to t = timeOut(me.string).new(0, #dummy , me)
end
on exitFrame me, aTimer
aTimer.forget()
end
--------</parent script "miawCloserClass">--------
The real fix is that "t = " has been added to the line where the
timeoutObject is created.
The MIAW is now "forgotten" already in the "new" handler, and the
task of the timeoutObject is now solely to be "the last keeper" of a
reference to the MIAW, making sure that the event leading to the
destruction of the MIAW, does not originate from within the MIAW
itself.
If you feel the urge to utter "mutual reference" or "explicitly void
the targetObject", then please test this code, and glean it over
again.
Without actually going back and rereading the reports of leaked
references to MIAWs, when "returning" MIAW references without
applying them, I'd wager that the two problems are related, and has
their root, in some common code which is used in both cases, and
potentially also in lots of other places, so it would be nice with a
"heads-up" from MACR, regarding other potential scenarios, that this
may affect.
Regards, Jakob
[To remove yourself from this list, or to change to digest mode, go to
http://www.penworks.com/LUJ/lingo-l.cgi To post messages to the list,
email [EMAIL PROTECTED] (Problems, email [EMAIL PROTECTED])
Lingo-L is for learning and helping with programming Lingo. Thanks!]