Proper OO structure for something simple

Posted by Tim Kuehn on 06-Jan-2012 13:36

  • I want to make an object corresponding to the current user.
  • The object's initial context will be set once and then be unchanged over the course of the session.
  • While I could easily accomplish  this with a static object, I'd prefer to avoid the headaches that static objects bring (to my particular context) and instead instantiate it once, refer to it's values when needed, and then have it go away when all non-static objects go away.

I know I can make a static property for the object, test it for valid-object on GET, and instantiate an instance when needed, however the problem with a static property is that it means the created object will always have a reference, making it - in essence - static as well.

Is there a way to accomplish what I'm after, or do I need to NEW the "user" object before I use it in each program's instance?

All Replies

Posted by Peter Judge on 06-Jan-2012 13:44

I know I can make a static property for the object, test it for valid-

object on GET, and instantiate an instance when needed, however the

problem with a static property is that it means the created object

will always have a reference, making it - in essence - static as well.

>

Not really.

Delete object Context:GetInstance.

Will kill the associated object instance. Next time you do the GET, a new one will be created.

Not necessarily agreeing with the use of statics, just saying that the property is static, not what it contains.

-- peter

Posted by Thomas Mercer-Hursh on 06-Jan-2012 13:48

There have been several publications on doing singletons without statics.

Posted by jmls on 06-Jan-2012 13:49

you want it to "be unchanged over the course of the session." , but

you don't want it static ? Confusing.

you can always do

delete object MyStaticProperty

if you want to remove the object from the session

Posted by Tim Kuehn on 06-Jan-2012 13:54

pjudge wrote:

Not necessarily agreeing with the use of statics, just saying that the property is static, not what it contains.

True - however a given non-static object will not be destructed until all references to it go away. If the "parent" reference is static, it, by definition, will never go away, ergo the object itself will not be destructed.

I think...

Posted by jmls on 06-Jan-2012 13:59

but the object stays for the length of the session ....

also, be very careful about classes that have use abl handles (like

a query or persistent procedure). These will not be Garbage

collected automatically.

Posted by Tim Kuehn on 06-Jan-2012 14:00

jmls wrote:

you want it to "be unchanged over the course of the session." , but you don't want it static ? Confusing.

you can always do

delete object MyStaticProperty

if you want to remove the object from the session

1) The "don't be static" constraint refers to the site this code will be run on, as using static "class members" have resulted in other issues.

2) Hmmm.... in which case maybe I could just walk SESSION:FIRST-OBJECT / :NEXT-SIBLING and delete the objects in order to clean out all the objects between runs of the 4GL editor....

Posted by jmls on 06-Jan-2012 14:39

1) we have a "static" class that comprises simply of properties to

singleton classes

2) won't work. They do not appear in the

session:first-object/next-object chain. But they are still there. And

I wasn't talking about editor runs. We had a system run out of sockets

because the persistent procedure wasn't being deleted, so the class

didn't get removed from memory and the socket released ...

Trying to come up with a specific simple test case .

Come to think about it, both cases where this happened involved

sockets ... perhaps that's the problem, not the handles ...

Posted by Tim Kuehn on 06-Jan-2012 15:12

So, here's a structure I'm thinking'll work as I want- as Julian mentioned, have a manager with static properties that point to instances that are used as singletons, and are non-static:


CLASS SessionManager:

DEFINE STATIC VARIABLE oUser    AS SessionUser      NO-UNDO.
DEFINE STATIC VARIABLE oSystem  AS SessionSystem    NO-UNDO.

DEFINE STATIC PUBLIC PROPERTY GetUser AS SessionUser
                        GET():
                                CheckUser().
                                RETURN(oUser).
                        END GET.
                        PRIVATE SET.

DEFINE STATIC PUBLIC PROPERTY GetSystem AS SessionSystem
                        GET():
                                CheckSystem().
                                RETURN(oSystem).
                        END GET.
                        PRIVATE SET.

METHOD PRIVATE STATIC VOID CheckSystem():
IF NOT VALID-OBJECT(oSystem) THEN
    oSystem = NEW SessionSystem().
END METHOD.

METHOD PRIVATE STATIC VOID CheckUser():
IF NOT VALID-OBJECT(oUser) THEN
    oUser = NEW SessionUser().
END METHOD.

END CLASS.

----------

Now, my test program shows that the resulting objects show up on the FIRST-OBJECt / NEXT-OBJECT chain, so they can be deleted and regenerated on successive runs, so one only has a "single" manager with static properties in order to implement the singleton property.

Test program to demonstrate follows.

NOTE: "SessionUser" and "SessionSystem" are both empty classes. (the class file only has CLASS ... END CLASS).

------------


DEFINE VARIABLE oSMgr       AS SessionManager           NO-UNDO.

DEFINE VARIABLE oSUser      AS SessionUser              NO-UNDO.
DEFINE VARIABLE oSSys       AS SessionSystem            NO-UNDO.

DEFINE VARIABLE oObj        AS Progress.Lang.Object     NO-UNDO.
DEFINE VARIABLE oNextObj    AS Progress.Lang.Object     NO-UNDO.

DEFINE VARIABLE is-v1       AS LOGICAL      NO-UNDO.
DEFINE VARIABLE is-v2       AS LOGICAL      NO-UNDO.

oSUser = SessionManager:GetUser.
oSSys  = SessionManager:GetSystem.

oObj = SESSION:FIRST-OBJECT.

REPEAT WHILE VALID-OBJECT(oObj):

    oNextObj = oObj:NEXT-SIBLING.

    DISPLAY
            oObj:tostring() FORMAT "X(30)"
            oObj:equals(oSUser)
            oObj:equals(oSSys)

            VALID-OBJECT(oObj) @ is-v1
        WITH DOWN.

    DELETE OBJECT oObj.

    DISPLAY
            VALID-OBJECT(oObj) @ is-v2
        WITH DOWN.

    DOWN.

    oObj = oNextObj.

END.

Posted by Tim Kuehn on 06-Jan-2012 15:21

jmls wrote:

1) we have a "static" class that comprises simply of properties to singleton classes

Ok - I modeled my test program after that.

2) won't work. They do not appear in the session:first-object/next-object chain. But they are still there. And I wasn't talking about editor runs. We had a system run out of sockets because the persistent procedure wasn't being deleted, so the class didn't get removed from memory and the socket released ...

As the test program shows, the object instances do appear in the FIRST/NEXT object chain.

Come to think about it, both cases where this happened involved sockets ... perhaps that's the problem, not the handles ...

I'm thinking if you didn't properly handle the socket shutdown / deletion in the destructor, they _may_ have hung around and caused your out-of-sockets problem.

Posted by jmls on 06-Jan-2012 15:49

1). I saw - but I think that this is easier on the eye :

def static property SessionFoo as class library.SessionFoo no-undo

get():

if not valid-object(SessionFoo) then SessionFoo = new

library.sessionFoo().

return SessionFoo.

end get. private set .

2) No, it was something to do with the auto GC. I put a message in the

destructor which never appeared. If I manually deleted the object,

things worked just fine

Posted by Tim Kuehn on 06-Jan-2012 16:00

jmls wrote:

2) No, it was something to do with the auto GC. I put a message in the destructor which never appeared. If I manually deleted the object, things worked just fine

Objects will not be GC'd if there are any references to them - are you sure all the references to the object were gone?

Posted by Tim Kuehn on 06-Jan-2012 16:04

jmls wrote:

1). I saw - but I think that this is easier on the eye :

  def static property SessionFoo as class library.SessionFoo no-undo

    get():

      if not valid-object(SessionFoo) then SessionFoo = new

library.sessionFoo().

      return SessionFoo.

    end get. private set .

That's another possibility.

The reason for my structure is to seperate the instantiation logic from the GETter logic. This allows for other portions of the code to call the instantiating method w/out having to reference the property, and if the object's instantiation isn't a straightforward NEW, it keeps the associated mess away from the property GETter.

The structure you're using certainly benefits from not needing to code a method per property though.

This thread is closed