Wiki Home

Ambiguous Or Contentious Object Ownership


Namespace: WIN_COM_API
Given the following simple object society:
LOCAL oContainer, oOther
oContainer= CREATE("Custom")
oContainer.AddObject("oContained", "Custom")
oOther= CREATE("Custom")
oOther.Addproperty("oRef", oContainer.oContained)

Then it can be said that object oContainer.oContained is ambiguously or contentiously owned because it is immutably contained by oContainer and also implicitly owned by oOther by virtue of the oOther.oRef reference. Depending on the version of VFP you are running, and the base classes of the objects involved, the class pedigrees, and other instance factors, you cannot say for certain what will happen when you try to release this system without prior Manual Garbage Collection.

The bottom line is this: in a decent design, objects that share lexical scope should not be abandoned with "uses" relationships between them at destruction. VFP's garbage collection is fairly good, always getting better, but never perfect. For more on all this, see Relationship Heuristics and beyond.
In the above, it seems clear that you need to take action in oOther to set its oRef property to NULL. This could be handled by, say, a CollectGarbage method that is called automatically if the object is destroyed. Beyond that, however, are there implications to letting the oOther and oRef simply go out-of-scope arbitrarily (such as by reaching the end of the procedure)? IOW, do you need to worry about specifically releasing oRef in this scenario, to ensure its GC occurs first? -- Randy P
It's hard to generalize. It depends on the base classes involved, whether oRef is a member defined in the class definition or alternately an added property (as it is here), and it also depends on the nesting of the containership hierarchies involved. VFP automatically cleans up these systems most of the time, which is what makes these types of bugs so insidious...-- Steven Black

This example also points out a few other bad object abuses. Since possibly some external process is doing the AddProperty, it becomes much harder for the object to clean up after itself during destruction. It would have to go through the effort of checking it's own properties via amembers() to find out if it is holding any object references. It would be much better for the AddProperty call to have been a call to a method of the object so it could track the objects being tacked on to it at runtime. I'm not trying to say that all runtime association/aggregation is bad, it can be quite useful indeed, but you need a well defined methodology to keep yourself from having dangling reference problems. -- ?df

I see no complexity here. I made this in my grid class. Add property in the init and populate it by object reference. In destroy check if property exists by PEMSTATUS command, than check if property holds valid object reference and than remove reeference (and possibly destroy object if needed), than remove property. Its much like resourse allocation/deallocation. Allocation here is just making reference, deallocation - removing it. In the clear classes design you usually know both places where need to do this, this is not a problem. I never had a problems with cross-referencing, just put appropriate code where required. There is a problem, however, when your objects deallocated automatically because some parent object deallocated. For such case I made following workaround:
- call at the form Release or QueryUnload event 'thisform.SETALL('lGoingToClose',.T.)
Now, if any object requires some preparations BEFORE any other object destoroyed, I define lGoingToClose property for it with Assign mathod and put object references releasing code there.
Now, when all above put into the base classes for form, and other classes in framework use this property to make clean up, I never have a single problem with referenses.

I guess it is better than any garbage collecting.

-- Vlad Grynchyshyn
Contributors: Steven Black, Vlad Grynchyshyn
Category Class Design
( Topic last updated: 2001.02.06 04:58:41 AM )