Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Articles
Search: 

Killing Objects
Oscar Zarate, March 1, 2007
Since the time we program with object orientation, we can play at being all-powerful, deciding the lifetime of our objects, and limiting "what they can, and what they can't, do". Now, in some cases these objects seem to take on a life of their own, and don't respect our wishes. As the old saying goe...
Summary
Since the time we program with object orientation, we can play at being all-powerful, deciding the lifetime of our objects, and limiting "what they can, and what they can't, do". Now, in some cases these objects seem to take on a life of their own, and don't respect our wishes. As the old saying goes, "the computer does what I tell it to do, not always what I want it to do".
Description

Since the time we program with object orientation, we can play at being all-powerful, deciding the lifetime of our objects, and limiting "what they can, and what they can't, do". Now, in some cases these objects seem to take on a life of their own, and don't respect our wishes. As the old saying goes, "the computer does what I tell it to do, not always what I want it to do".

But, why does this happen? Normally this happens when we haven't done a good design, or haven't correctly established the scope of our objects; this will be the subject of this article.

Scope

Objects are normally created and assigned to a variable.

Visual FoxPro has three different scopes that can be assigned to a variable, namely Public, Private, and Local.

Public is the definition we should never used, since a public variable can be accessed from any place of our application, even from a parent object or an object totally unrelated to the object assigned to a public variable. As a result, in some cases we would have access to an object, in others we won't; or an object mysteriously changes its value (anybody, in any part of the application, can change the value, and this will affect other parts of the program). Conclusion: Our applications should not have any public variable.

Private is the scope we should reserve for the cases where we need a variable to be accessed by some object that is related to the object where the variable was created. The classical example is when in a program we create a variable that will be printed in a report. Conclusion: Use sparingly.

Local is the scope we should assign to all our variables, since this makes it available only within the method or procedure where it was created. Conclusion: The fact that we define a variable as local will guarantee that, in most cases, when a variable ends its scope (the method or procedure that creates it finishes ejecution), our object will die.

 
LOCAL loFirst, loSecond

loFirst = CREATEOBJECT("MyFirstClass")
loSecond = CREATEOBJECT("MySecondClass")

RETURN 

*---------------------------------------------
DEFINE CLASS MyFirstClass as Custom

PROCEDURE DESTROY
  WAIT WINDOW This.Name 
ENDPROC
ENDDEFINE


*---------------------------------------------
DEFINE CLASS MySecondClass as MyFirstClass
ENDDEFINE

In this simple example, we see that, even though we didn't explicitly kill the objects loFirst and loSecond, both die when the scope where they were created finishes.

Note: It is recommended, as a good practice, to explicitly kill the objects. This would be as in the following example (that is not much different from the previous one, but explicitly kills the object instances); from the two possibilities of eliminating an object, I prefer to assign NULL rather than RELEASE, since an object assigned a NULL in an evaluation will return "X" in a type evaluation, whereas an object freed with RELEASE will return "U" as if it had never existed.

 
LOCAL loFirst, loSecond

loFirst = CREATEOBJECT("MyFirstClass")
loSecond = CREATEOBJECT("MySecondClass")

loFirst = NULL
loSecond = NULL

RETURN 

*---------------------------------------------
DEFINE CLASS MyFirstClass as Custom

PROCEDURE DESTROY
  WAIT WINDOW This.Name 
ENDPROC
ENDDEFINE


*---------------------------------------------
DEFINE CLASS MySecondClass as MyFirstClass
ENDDEFINE

A few paragraphs before, I said "in most cases", and here we must have the design idea very clear, and not create a monster that decides for itself how long it should live, even if we decide to kill an object, either by assigning a NULL to the object or executing the RELEASE instruction. Here we can see some examples of a bad design that results in our objects not being killed when we decide to kill it.

In this first example, we can see one of the cases where VFP can't destroy objects, even when they are out of scope.

 
*   To understand this example, execute this program twice from the Command Window,
*   and then type Clear All in the Command Window.
*
*   Before the "Clear All", the objects will remain in memory.
*   After the "Clear All", the Destroy method will execute twice for every object.

LOCAL loFirst AS Object, loSecond AS Object

*-- Create an instance of MyFirstClass and assign it to loFirst 
*   at this moment, the name table index (for MyFirstClass)
*   has a value of 1
loFirst = CREATEOBJECT("MyFirstClass")
MESSAGEBOX("First object created")

*-- Create an instance of MySecondClass and assign it to loSecond
*   at this moment, the name table index (for MySecondClass)
*   has a value of 1.
loSecond = CREATEOBJECT("MySecondClass")
MESSAGEBOX("Second object created")

*-- Now, the object loFirst is assigned a property in loSecond
*   and the Name Table Index (for MyFirstClass) becomes 2
loSecond.Pointer = loFirst
MESSAGEBOX("Second object has a pointer to the first object")

*-- Now, the object loSecond is assigned a property in loFirst
*   and the Name Table Index (for MySecondClass) becomes 2
*   with a circular reference
loFirst.Pointer = loSecond 
MESSAGEBOX("First object has a pointer to the second object, and a circular reference is created")

MESSAGEBOX("Even when the variables get out of scope, DESTROY is not executed " +;
  + CHR(13) + CHR(13) + "REMEMBER TO EXECUTE CLEAR ALL AFTER THE SECOND RUN. ")


RETURN 

*---------------------------------------------
DEFINE CLASS MyFirstClass as Custom
Pointer = NULL

PROCEDURE DESTROY
  MESSAGEBOX("Destroying " + This.Name)
ENDPROC
ENDDEFINE

*---------------------------------------------
DEFINE CLASS MySecondClass as MyFirstClass
ENDDEFINE

In this second example, we see a bad design, with a pointer to an object that should have been destroyed, due to the pointer it still exists.

 
LOCAL loForm AS FORM, loTextbox AS TEXTBOX

* -- In this example, we are doing two different things:
*    1 – Creating an instance of a form (MyForm)
*    2 – The form creates a Textbox
*    Name Table Index (for the form) is 1
*    Name Table Index (for the textbox) is 1
loForm = CREATEOBJECT("MyForm")

* -- Another pointer is assigned to the Textbox
*    Name Table Index (for the textbox) is 2
loTextbox = loForm.txtTest
READ EVENTS

*-- Now, Name Table Index (for the form) will be 0
*   The method Destroy is executed, and the Name Table Index (for the textbox) goes back to 1
*   But, since the textbox still has a reference to the form, it can't be destroyed.
loForm = .NULL.

=MESSAGEBOX('Variable loform has been assigned a NULL' + CHR(13) + CHR(13) + ;
  '  - loForm = .Null.' + CHR(13) + CHR(13) + ;
  'But it can't be freed from memory, since a circular reference to the textbox exists' + CHR(13) + ;
  'The value of VARTYPE(loForm) is "' + VARTYPE(loForm) + '"' + CHR(13) + ;
  'and the value of loTextbox.value is "' + ALLTRIM(loTextbox.VALUE) + '"' + CHR(13) + CHR(13) + ;
  'and ... the form is visible.')

*-- Finally, the Garbage Collector can eliminate the references 
loTextbox = NULL

=MESSAGEBOX('Finally, the form is dead' + CHR(13) + CHR(13) + ;
'The reference to the textbox was assigned a NULL and the form was released.' + CHR(13) + CHR(13) + ;
'  - loTextbox = NULL')

RETURN


DEFINE CLASS MyForm AS FORM

  ADD OBJECT txtTest AS TEXTBOX
  ADD OBJECT lblTest AS LABEL

  PROCEDURE INIT()

    WITH THIS
      .txtTest.LEFT    = 10
      .txtTest.TOP     = 40
      .txtTest.VALUE   = "Write something:"
      .txtTest.WIDTH   = 280
      .lblTest.LEFT    = 10
      .lblTest.TOP     = 80
      .lblTest.WIDTH   = 280
      .lblTest.CAPTION = "When you finish, press the X on the form to close it"
      .caption         = "Demo: multiple references to an object " + TTOC(DATETIME(),1)
      .AUTOCENTER = .T.
      .VISIBLE    = .T.
    ENDWITH

  ENDPROC

  PROCEDURE DESTROY
    MESSAGEBOX("Destroying the form... ")
    CLEAR EVENTS
  ENDPROC
ENDDEFINE

Conclusion

After doing some research on the scope of objects, assigning a NULL, using RELEASE, and thinking about the design, we can state:

  • A good design is very important, avoiding circular references and maintaining control of the pointers to objects.

  • We must define the object scope well, since if the design is good, VFP will do a good job of getting rid of all that is not needed after finalizing a procedure.

  • Using the recommendations of sound practices, and assigning the variables that are pointers to objects a NULL value, we indicate that an object should die.

With these recommendations, we can have a feeling of being all-powerful over our applications.

Oscar Zarate, National Australia Bank
Oscar Zárate is Bachellor in Business Administration, and Systems Analyst. He works as a developer since 1986, starting with the first versions of FoxBase, through Clipper, until the current versions of Visual FoxPro. He is MCP in Visual Basic .NET. He has also worked, among other tools, with Visual Basic, ASP, XML and SQL Server. He was the Treasurer of a the Microsoft User Group community (www.mug.org.ar). Currently, he is living in Australia after 36 years living in Argentina and now he is working for National Australia Bank after working more than one year for Triveni Infotech in Melbourne. www.oscarzarate.com.ar
More articles from this author
Oscar Zarate, June 1, 2003
A few years ago Microsoft launched a contest to award research projects among universities. On that topic, we interviewed Carlos Alejandro Pérez, Director of the project in the National Technological University (UTN), branch of the province of Chaco (Argentina). His project was selected from a...
Oscar Zarate, September 1, 2003
On August 7th and 8th took place at the Village Recoleta Complex this international event whose motto was "The more you know, the farther you reach". There were two days where the top speakers of Argentina gathered to bring out a true mega-event. Even more, the audience could take advantage of...
Oscar Zarate, March 1, 2003
Handling large text volumes is always a complication for systems, and mainly for ourselves, developers. When we have the need to handle fields with vast amounts of text our tribulations begin, and this is even worst if the user needs to search for a single word; of course not the first word of a phr...
Oscar Zarate, February 1, 2003
Introduction Visual SourceSafe (VSS) is the version control (VCS) and source-code management system provided by the Microsoft Visual Studio product family. A version control system basically lets you manage the source programs within a development group, maintaining the entire modificati...