Hello,
I have performance issues with my ABL classes (Progress 10.2b).
Are there some best practice tips for Object properties ?
I try to use lazy instantiation on my properties to avoid infinite loops caused by circular references, but I think the properties are evaluated during the object instantiation, defeating the benefits of using lazy instantiation.
Here is an example:
DEFINE PRIVATE VARIABLE cl_enterprise AS NameSpace.Enterprise NO-UNDO. DEFINE PUBLIC PROPERTY pin_EntId AS INTEGER NO-UNDO GET. PRIVATE SET. DEFINE PUBLIC PROPERTY pcl_Enterprise AS NameSpace.Entreprise NO-UNDO GET(): IF NOT VALID-OBJECT( cl_enterprise ) AND pin_EntId > 0 THEN DO : cl_enterprise = NEW NameSpace.Enterprise( pin_EntId ). END. RETURN cl_entreprise. END GET. PRIVATE SET( INPUT pr_cl_valeur AS NameSpace.Entreprise ): THIS-OBJECT:cl_enterprise = pr_cl_valeur. END SET. CONSTRUCTOR PUBLIC Contact( INPUT pr_in_EntId AS INTEGER ): SUPER(). ASSIGN pin_EntID = pr_in_EntId. END CONSTRUCTOR.
I'm trying to instantiate the object cl_enterprise on first access. Am I doing something wrong ?
Lazy instantiation is to delay creating a class until it's actually needed - it won't solve problems like unintended circular references and their related issues.
Looking at your code, I'd just make the "SET" private and not have any code in it, since pcl_Enterprise is never referred to directly in this code sample.
Beyond that - have you tried running this using the debugger to see where the execution path is actually going?
Thanks for your reply.
This is a code sample, I actually need to keep the code in the private set.
I try to do some lazy instantiation so that when an object is instantiated, its object properties aren't until accessed. But as the properties get evaluated during the execution of the constructor, the lazy instantiation does not work.
About the circular reference issue:
Say we have a class Company with a property Director, and a class Director with a property Company.
To me it seems natural to do this way.
However there is a circular reference, and it's dangerous (for example for serialization) which leads me to think that there must be a better way to do this without a circular reference. I just can't find how.
Any idea?
I did a few tests. On Windows properties don't get evaluated during the instantiation. But on Unix they are. Weird!
Maybe this has to do with compilation. On Unix my source files aren't compiled, but on Windows they are automatically compiled.
Then I'm confused, as I'd expect you to be setting pcl_enterprise in the SETter, not cl_enterprise. If you're setting cl_enterprise in the setter, then the object reference in the GETter will be lost when the SETter is called.
As for the circular reference, I'd surmise you need to split the "company" and "director" classes up so they're not referencing each other that way and then use a container class to hold both of them. Usually I'd look at the more general case (Company) would hold the less general case (Director). If the director class needs to know which company the director belongs to, then pass the Company reference to the Director's constructor.
do a full recompile of the project on both - if you have different behavior between the platforms, then that's a bug and needs to be reported.
Thanks. That makes sense.
As for why I use a private variable for the Get/Set, that's because once I got a Get loop when I do the following:
DEFINE PUBLIC PROPERTY pA AS test.A GET(): IF NOT VALID-OBJECT ( pA ) THEN DO : pA = NEW test.A(). END. RETURN pA. END GET. PRIVATE SET.
As "pA" is self-referenced inside the getter itself, there was a loop (in the "IF NOT VALID-OBJECT( pA )" line).
This is what I do to implement delayed instantiation:
USING Answers.DelayedInstantiation.* FROM PROPATH. CLASS Answers.DelayedInstantiation.DelayedInstantiationParent: DEFINE PUBLIC PROPERTY DelayedChild AS DelayedInstantiationChild NO-UNDO GET: IF NOT VALID-OBJECT(THIS-OBJECT:DelayedChild) THEN DelayedChild = NEW DelayedInstantiationChild(). RETURN(THIS-OBJECT:DelayedChild). END GET. PRIVATE SET. END CLASS.
don't see anything wrong with that, I would just skip the setter on the property as that it's just a proxy to the private variable keeping the actual reference
using a private variable to keep the reference is mostly just to avoid useless object creation on destructor if it happens not to be instantiated by that time as will happen in Tim version, aka create something when actually trying to clean-up.
other than that I've never seen a behavior where properties are evaluated on constructor unless some piece of code fired by the constructor will access those properties so you better check out what is happening in those constructors, your class and base class(es)
Actually, thinking about this, the OP needs to create a factory that'll create both the Director and the Company objects and then pass the appropriate company / director object to the object being created for it to use.