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!]

Reply via email to