Is this cheating ?

Posted by jmls on 29-May-2009 02:31

I need to create a number of dynamic pictures, and may often need to delete them and recreate some new ones. What is the best way of managing the objects ? When does the garbage collection occur ?

Now, a little bit of code

DEF VAR ultraPictureBoxGrid AS Infragistics.Win.UltraWinEditors.UltraPictureBox EXTENT .

EXTENT(ultraPictureBoxGrid) = 5.

ultraPictureBoxGrid[1]                   = NEW Infragistics.Win.UltraWinEditors.UltraPictureBox().

ultraPictureBoxGrid[2]                   = NEW Infragistics.Win.UltraWinEditors.UltraPictureBox().

ultraPictureBoxGrid[3]                   = NEW Infragistics.Win.UltraWinEditors.UltraPictureBox().

ultraPictureBoxGrid[4]                   = NEW Infragistics.Win.UltraWinEditors.UltraPictureBox().

ultraPictureBoxGrid[5]                   = NEW Infragistics.Win.UltraWinEditors.UltraPictureBox().

MESSAGE VALID-OBJECT(ultraPictureBoxGrid[1]) SKIP

        VALID-OBJECT(ultraPictureBoxGrid[5]) SKIP

        view-as ALERT-BOX TITLE "#1".

DELETE OBJECT ultraPictureBoxGrid[1]. 

MESSAGE VALID-OBJECT(ultraPictureBoxGrid[1]) SKIP

        VALID-OBJECT(ultraPictureBoxGrid[5]) SKIP

        view-as ALERT-BOX TITLE "#2".

ultraPictureBoxGrid = ?. 

MESSAGE VALID-OBJECT(ultraPictureBoxGrid[1]) SKIP

        VALID-OBJECT(ultraPictureBoxGrid[5]) SKIP

        view-as ALERT-BOX TITLE "#3".

If you run this code, you will see in "#3" that object[5] is no longer valid. Is this an easy way of deleting a large number of objects (they are not referenced anymore) or am I just hiding the problem ?
I know that I can store the objects in a Temp table, and then loop through, deleting each one. However, is this more efficient ?
Thanks, as always, for any advice.

All Replies

Posted by Matt Baker on 29-May-2009 08:14

This is garbage collection at work.  You can explicitly release an object using "delete object..." which destroys the actual object itself and invalidates all references to the object.  Or you can just remove all the references to it (by setting it to null).  The garbage collector will eventually clean it up when the last reference is gone.

To see it more completely, try this:

DEF VAR ultraPictureBoxGrid AS Infragistics.Win.UltraWinEditors.UltraPictureBox EXTENT .

EXTENT(ultraPictureBoxGrid) = 2.

ultraPictureBoxGrid[1]                   = NEW Infragistics.Win.UltraWinEditors.UltraPictureBox().
ultraPictureBoxGrid[2]                   = NEW Infragistics.Win.UltraWinEditors.UltraPictureBox().

def var pictureBox1 as Infragistics.Win.UltraWinEditors.UltraPictureBox no-undo.
def var pictureBox2 as Infragistics.Win.UltraWinEditors.UltraPictureBox no-undo.

pictureBox1 = ultraPictureBoxGrid[2].
pictureBox2 = pictureBox1.

message valid-object(pictureBox1) valid-object(pictureBox2) valid-object(ultraPictureBoxGrid[2]) view-as alert-box.

/* this only invalidates the array */
ultraPictureBoxGrid = ?.

message valid-object(pictureBox1) valid-object(pictureBox2) valid-object(ultraPictureBoxGrid[2]) view-as alert-box.

/* this invalidates both pictureBox variables */
delete object pictureBox1.

message valid-object(pictureBox1) valid-object(pictureBox2) valid-object(ultraPictureBoxGrid[2]) view-as alert-box.



Be aware though that if something implements "IDisposable" or has a Dispose() method, you are expected to call Dispose() on the object before releasing the last reference to it.  This is normally true for objects that contain unmanaged resources.  Things that fall into this category are Image objects (I can't think of any others right now).

You can see this at work in the visual designer.  Create a form, add an ImageList object to the form and add an image to the form.  You'll see the visual designer generates code to call Dispose() on the components variable.  The constructor for ImageList objects accepts the components object and internally adds itself to the components controls collection by calling components:Controls:Add(this-object).  The components object then takes care of calling dispose on the ImageList object when Dispose() is called on the components object.

Posted by GregHiggins on 01-Jul-2009 06:37

   > Be aware though that if something implements "IDisposable" or has a Dispose() method, you are expected to call Dispose() on the object before releasing the last reference to it.

Even if we assume that all objects with a Dispose method implement IDisposable, there is no way to ask an object if it implements IDisposable other than to attempt to cast it to an IDisposable and ignore any failure.

Just off the top of my head:

define property myObjVar as some.object no-undo get.

  set ( o as some.object ):

    if valid-object ( o ) then myObjVar = o.

    else if o eq ? then do on error undo, throw new Progress.Lang.AppError ( "Not Disposable" ):

       CAST ( myObjVar, "System.IDisposable" ):Dispose ( ).

       catch  e as Progess.Lang.ProError:

       end.

    end.

  end.

Posted by Admin on 01-Jul-2009 06:59

Won't the TYPE-OF function work?

Posted by GregHiggins on 01-Jul-2009 07:35

Of course it will. Thanks!

define property myObjVar as some.object no-undo get.

  set ( o as some.object ):

    if valid-object ( o ) then myObjVar = o.

    else if o eq ? then do:

      if type-of ( myObjVar, "System.IDisposable" ) then CAST ( myObjVar, "System.IDisposable" ):Dispose ( ).

      myObjVar = ?

    end.

  end.

Posted by Admin on 01-Jul-2009 07:43

Of course it will. Thanks!

I'm glad that works :-)

I am - by the way - never quoting the typenames in TYPE-OF and CAST methods to make clear that the type is evaluated at compile time, not at runtime.

Posted by GregHiggins on 01-Jul-2009 08:09

Good point. There are instances where the names must be quoted, but with that exception, I think I'll adopt a the same rule: Quotes only if required for compile time classes.

This thread is closed