Understanding the Delete Keyword.

In the comments of my previous post about how the garbage collector works in Flash Player 9, Cédric Néhémie asked a great question about why using delete on a property of a sealed (non-dynamic) class throws an error in ActionScript 3, and whether it will delete the actual object in memory.

There isn’t a lot of documentation on this topic, and what there is is hard to find, so much the following is conjecture and interpolation from related exploration, but I think it is fairly accurate. If not, please let me know in the comments – I don’t want to lead anyone astray.

My understanding is that the delete keyword deletes the actual variable definition, not just the variable’s value. This of course frees any reference it was holding, potentially freeing that object for garbage collection (as described in my previous article). It will not delete the referenced object from memory directly.

ActionScript 2

In AS2, this behaviour was virtually unnoticeable, as the player did not have support for sealed (non-dynamic) classes at run-time. This meant that deleting a variable definition was functionally almost identical to setting the variable’s value to undefined. Because of this, the compiler never bothered throwing errors related to delete. There were only a few rare cases where differences could be seen. For example, in AS2 try deleting a MovieClip instance’s onPress handler and mousing over the clip. Now try setting its onPress to undefined. Even though tracing onPress will return “undefined” in either case, you will get a hand cursor on the one you set to undefined but not on the one you deleted. I’m quite sure this is because the player looks for the existence of the onPress handler definition, not a value, when determining if it should show the hand cursor.

ActionScript 3

AS3 on the other hand supports sealed classes at run-time. All classes are sealed by default, unless they are explicitly declared to be dynamic. You may not modify the definition of a sealed class (or its instances) by adding or removing members at run-time. Because of this, and to comply with the ECMAScript specification, delete will only remove dynamically created properties of dynamic classes. It will not even remove local (method level) variables. This is alluded to in the “What’s new for the PrintJob class using ActionScript 3.0” doc (for whatever reason):

In ActionScript 2.0, you could use delete to remove an object or on an object property. In ActionScript 3.0, the delete operator is now ECMAScript compatible, meaning delete can only be used on a dynamic property of an object.

If you try to use delete on anything other than a dynamic property, it will trigger a compiler error (in strict mode) that looks something like this:

1189 > Delete removes dynamically defined properties from an object. Declared properties of a class can not be deleted. This error appears only when the compiler is running in strict mode.

In AS3, delete will return a boolean value indicating whether it was successful (ie. the property no longer exists when the operation completes). You can test this with the following code:

var t:* = new Timer(15); // no typing to get around the compiler error
trace(delete(t.delay)); // traces false, object is sealed so can't delete
trace(t.delay); // 15 - delete never occurred
var o:* = {fun:"stuff"};
trace(delete(o.fun)); // traces true, object is dynamic so can delete
trace(o.fun); // undefined - delete occurred
trace(delete(o.foo)); // true, because foo is not defined after delete

UPDATE: Added information to the article about delete returning a boolean success value.

UPDATE 2: Rewrote some sections slightly based on new information found in the AS3 docs.

Grant Skinner

The "g" in gskinner. Also the "skinner".

@gskinner

20 Comments

  1. Or trace(delete(o.work)); // traces true, no “work” exists after the delete completes.

  2. James – right. Good addition. I’ve added it above.

  3. I forgot to mentionned that I’ve got the same error with a local variable :

    var o:Object = new Object();

    trace (delete (o)); // trace false

    trace (o); // [object Object]

    It’s like the only goal of delete keyword in AS3 is to remove a dynamically defined property from a dynamic class.

    Strange isn’t it ?

  4. “It’s like the only goal of delete keyword in AS3 is to remove a dynamically defined property from a dynamic class.”

    That’s how it behaves in AS1/AS2. You can’t delete a local variable.

  5. Doing some more digging, I’ve found that that’s actually exactly right Cédric. From (of all places) the PrintJob documentation for AS3:

    “In ActionScript 2.0, you could use delete to remove an object or on an object property. In ActionScript 3.0, the delete operator is now ECMAScript compatible, meaning delete can only be used on a dynamic property of an object.”

  6. “That’s how it behaves in AS1/AS2. You can’t delete a local variable.”

    You’re right, sorry for the mistake, sometimes I don’t think enough 😛

    And nom the question is : How we can delete an object stored in a sealed class property ?

    (And why MM/Adobe don’t provide anything to manage weak references, like they do in EventDispatcher ? )

  7. C̩dric Рyou can never specifically delete an object. You can null the value of the property though, which deletes the reference to the object.

    Weak references will be the topic of one of my upcoming articles. You’re getting ahead of me here. :)

  8. Please Help!!

    I’m busy building a media player that loads an external swf containg a FLVPlayback component.

    In the players ‘collapsed’ state, I need to delete the MovieClip declared in my class declaration: private var _videoPlayerMc:MovieClip;

    I get the following error:

    1189: Attempt to delete the fixed property _videoPlayerMc. Only dynamically defined properties can be deleted.

    How can i go about doing this?

  9. Doesn’t really clear up any issues with the garbage collector, though. It deletes the reference, sure, but items are still not being flagged for GC. Don’t know why. See:

    var o:* = {fun:new Timer(100, 100)};

    o.fun.addEventListener(“timer”, function(e:Event) { trace(“timer”); });

    o.fun.start();

    trace(delete(o.fun));

    trace(o.fun);

    Output:

    true

    undefined

    timer

    timer

    timer

    timer

    … (repeats 100 times)

    The timer, which longer has any references AFAICT, is not being collected.

  10. @Andy

    There IS still a reference. You created a reference when you added an event listener.

  11. Lanny, I thought that the whole purpose of the garbage collector was that IT would remove the event listener for you if you forget to after nulling an object. If we have to remove the event listener, as in you explaination, then what is the use of the garbage collector?

    Really confused now!

  12. In Andy’s example the Timer instance should be available for cleanup by the garbage collector. Contrary to what Lanny said, there are no active references to it (adding the listener created a reference to the anonymous function from the timer, not the other way around).

    What is causing the behaviour you are seeing is the fact that the GC uses a deferred indeterminate model for running cleanups. This means that you have no way of knowing when it will clean up the timer. See my other articles on this subject (search for Resource Management in the side bar) for more information.

  13. I thought that you had to specify the useWeakReference parameter in addEventListener, since it defaults to false (won’t useWeakRefernce ie:

    var o:* = {fun:new Timer(100, 100)};

    o.fun.addEventListener(“timer”, function(e:Event) { trace(“timer”); }, false, 0, true); // the last true is the weak reference boolean

    o.fun.start();

    Then delete will actually make it available for GC?

  14. Sorry to have to re-post so soon but I just remembered the System.gc() method which can be run in the debug player in Flex3, and you don’t even need to use the profiler, so it works without Flex Professional!

    The following code confirms my thought about useWeakReference in the addEventListener method…

    package

    {

    import flash.display.Sprite;

    import flash.events.TimerEvent;

    import flash.system.System;

    import flash.text.TextField;

    import flash.utils.Timer;

    public class MaskTester extends Sprite

    {

    public function MaskTester()

    {

    var tf:TextField = new TextField();

    tf.text = “Garbage Collector Test Running…”;

    tf.scaleX = tf.scaleY = 5;

    tf.autoSize = “left”;

    this.addChild(tf);

    var o:* = {fun:new Timer(1000, 1000)};

    o.fun.addEventListener(“timer”, function(e:TimerEvent):void { trace(“o.fun”, e.currentTarget.currentCount);

    });

    o.fun.start();

    trace(delete(o.fun));

    trace(“o.fun”, (o.fun));

    o.pun = new Timer(1000, 1000)

    o.pun.addEventListener(“timer”, function(e:TimerEvent):void { trace(“o.pun”, e.currentTarget.currentCount);

    },false, 0, true);

    o.pun.start();

    trace(delete(o.pun));

    trace(“o.pun”, (o.pun));

    System.gc();

    // traces “fun 1″-1000

    // but not “pun 1″ -1000

    }

    }

    }

  15. i have been reading about this for a bit, and i cannot figure out how to completely remove a swf i loaded.

    i used

    var loader:Loader = new Loader();

    loader.load(new URLRequest(“mySwf.swf”));

    cont.addChild(loader);//cont existing on timeline

    then i try removing it like this

    cont.removeChildAt(0);

    but i can still hear it, i tried using delete() but same thing.

    i might be just doing it all the way wrong.

    can i have some help please?

  16. Does anyone know if timers are ignored by the gc? I’ve seen posts other places (http://www.bit-101.com/blog/?p=1169#comment-251831) that suggest this. Running a manual gc with a running timer, I can never get the timer to go away. I was under the impression that Timer was like Loader or Tween in that you had to always keep a reference of it to avoid it getting gc’d. I’m thinking now this isn’t the case.

  17. Puh, I m searching now for decades for concret

    code snipps/ examples to resolve the memory problems ;-). I learned a lot about defining, removing eventlisteners etc.

    BUT:

    Please can someone give a code snipp

    how to defently remove objects from memory?

    And can someone please translate/illustrate this statement with an example:

    Make sure you clean up Asynchronous objects directly, nulling these

    objects doesn’t unhook them from the Flash player.

    – Timer

    – Loader

    – URLLoader

    – File/SQLite

    Should we use delete properties to remove an object from memory? I am confused.

  18. stevie, I think you might find what you search here:

    http://olegfilipchuk.com/

  19. What if the dynamically created property is created from a dynamic name? Since the name of the property is dynamic, I can’t specify it.

  20. @Andre Dickson

    you can delete the property using the bracket syntax

    delete obj[“dynamicPropertyName”];

Comments are closed.