Deleting a lazy object

Posted by jmls on 26-Jun-2012 01:03

Trying to incorporate some lazy instantiation (only creating an object when it is referenced) I came across an issue.

given this property

def public property Salesrep as sports.Model.Salesrep no-undo

    get():

      if not valid-object(Salesrep) then

      do:

        assign Salesrep       = new sports.Model.Salesrep().

      end.

      return Salesrep.

    end get . private set .

this works fine.

However, how can I force a deletion of the object if and only if it has been instantiated ?

if valid-object(SalesRep) always will return true because the property getter will create it if it doesn't exist

is there some trick to check the validity of the object without going through the getter ?

All Replies

Posted by Admin on 26-Jun-2012 01:16

is there some trick to check the validity of the object without going through the getter ?

SESSION:FIRST-OBJECT .... with TYPE-OF

or create a SalesrepExists or DeleteSalesrepIfExists method in your factory.

Posted by jmls on 26-Jun-2012 01:41

Yeah, I am doing something like that. I was just being lazy , and not

wanting to declare a "shadow" variable for each object.

Don't understand the reference to system:first-object - how could that be used ?

thanks, though !

Posted by Admin on 26-Jun-2012 02:11

o = SESSION:FIRST-OBJECT .

DO WHILE VALID-OBJECT (o):

IF TYPE-OF (o, SalesRep) THEN DO:

MESSAGE "Julian happy, almost forgot that Italy is in the semi-final now".

LEAVE.

END.

o = o:NextSibling .

END.

Posted by jmls on 26-Jun-2012 02:21

1) that doesn't work if I have more than one customer object : there

then may be more than 1 state instance

2) You complete and utter .... you just wait. One day. One day we will

actually practice penalties and then you will suffer

Posted by Admin on 26-Jun-2012 02:31

Re the penalty kicks: never, ever, especially not in a match that counts

Re the objects: I was on a singleton route here. But does the SalesRep object know its parent? In that case, you could loop through all Salesreps like shown and ask those for their parent and compare.

If that's not given you'll have to go down the route of an additional variable in your customer class.

Posted by Tim Kuehn on 26-Jun-2012 08:26

Two options:

1) Use a method for your LI and the "does this object exist" check.

2) Use the existing property, and include a "sentinel" variable which prevents it from creating a new object, something like so:

DEFINE VARIABLE is-instantiated-check   AS LOGICAL      NO-UNDO.

def public property Salesrep as sports.Model.Salesrep no-undo
    get():

      if not valid-object(Salesrep) AND
         NOT is-instantiated-check then
      do:
        assign Salesrep       = new sports.Model.Salesrep().
      end.

      return Salesrep.
    end get . private set .

def public property IsSalesrepInstantiated as LOGICAL   no-undo
    GET():
        ASSIGN is-instantiated-check = YES.
        IsSalesrepInstantiated = VALID-OBJECT(Salesrep).
        ASSIGN is-instantiated-check = NO.
        RETURN(IsSalesrepInstantiated).
    END GET.

    PRIVATE SET.

(This was written but not tested....actual performance or compilability may vary...)

Posted by Thomas Mercer-Hursh on 26-Jun-2012 09:33

There is another clue in Mike's message.  It sounds like you are having the Customer object create the Salesrep object.  If, instead, the Customer object invokes a method in a factory object to create the Salesrep object then you have a central place to keep track of what Salesrep objects still exist.  E.g., it could keep a temp-table of the requesting object's ID and the resulting Salesrep objects.  Then, the Customer can call DeleteMySalesRep ( myID ) and the factor can look up to see whether there is actually a rep existing for that ID.

Posted by jmls on 26-Jun-2012 09:56

Far to much fluff. All I want to track is that the salesrep is

appropriate for that customer. No more. No less. Having a "shadow"

logical variable solves the problem. What do I want to go around

writing object managers for when I have garbage collection doing that

for me ?

On 26 June 2012 15:33, Thomas Mercer-Hursh

Posted by Thomas Mercer-Hursh on 26-Jun-2012 10:08

Because factories are good practice regardless of lazy instantiation or other issues.  One place that creates a given object type(s) regardless of where or why it is used.  That "one place" is pretty central to OO thinking.

Posted by jmls on 26-Jun-2012 10:26

ok, I'll bite seeing as you did

what's the difference between

x = new foo().

and

x = fooFactory:NewFoo().

if there is stuff that has to happen around a foo() creation,

shouldn't that be in the foo class ?

If the factory manages stuff, how do you avoid someone bypassing the

factory and simply calling new foo() ?

On 26 June 2012 16:08, Thomas Mercer-Hursh

Posted by marko.rueterbories on 26-Jun-2012 10:36

Hey Julian,

If you wanna prevent someone from bypassing the factory you have to implement a private default constructor in foo and a second public constructor taking the factory as the input parameter.

That’s the best way of doing this.

Regards,

Marko

Posted by jmls on 26-Jun-2012 10:41

I thought that the factory was responsible for creating the foo instance ?

On 26 June 2012 16:36, Marko Rueterbories

Posted by Thomas Mercer-Hursh on 26-Jun-2012 10:41

There can easily be things associated with foo that are not a part of foo.  One of the more obvious is this kind of housekeeping.  Another possibility is pre-validation that the values one has in hand are valid for creating a valid foo object.  Another is managing singletons without the side effects of statics.  Another could be reference counting where usage was complex (although one might question the decomposition).

Posted by Thomas Mercer-Hursh on 26-Jun-2012 10:51

It is.  There was a recent thread ... yours, as I recall, where people talked about various levels of how much one wanted to absolutely prevent someone from misusing the framework vs trusting them to do the right thing and various proposals of how to enforce the rules if rules were needed.  They apply equally here.

Posted by gus on 26-Jun-2012 12:02

That's disgusting.

Posted by Peter Judge on 26-Jun-2012 12:11

jmls wrote:

Far to much fluff. All I want to track is that the salesrep is

appropriate for that customer. No more. No less. Having a "shadow"

logical variable solves the problem. What do I want to go around

writing object managers for when I have garbage collection doing that

for me ?

If the Customer truly cares about the Salesrep, pass it into the Customer's constructor (this is how I would pass mandatory values).

oCustomer = new Customer(new Salesrep()).

Then your valid-object check always works *as the next programmer who comes along would expect it to* (and that next programmer might even be you). You can pass the salesrep in via a factory method or some other construct. Or if you don't want to use the constructor, then have the factory set the Salesrep property value (this is how I would pass non-mandatory values). But having jiggery-pokery in the property getter when you don't always want that value to be valid, is not how I would proceed.

-- peter

Posted by Thomas Mercer-Hursh on 26-Jun-2012 12:20

I mostly agree, Peter.  Lazy instantiation should be a property of the system, not of the parent object itself.   Really, Salesrep is either a mandatory association or it isn't.  Here, it isn't because there is no provision for it to be undefined, only for the object itself to not exist.  So, from the point of view of the Customer object, the relationship is mandatory and should be available at any time.  From the outside, we know that it is not always needed, so we are interested in lazy instantiation, but this is a matter of context and the system, not the Customer object itself, so that logic should not be in the Customer object.

BTW, I don't think it should get passed in the constructor, but that discussion has already occurred elsewhere on this forum.

Posted by jmls on 26-Jun-2012 16:04

what's disgusting ? The code or the evil message ?

Posted by jmls on 26-Jun-2012 16:08

yeah, this is what I have

  def protected property HasValidServer as logical no-undo protected get . private set .

  def public property Server as dotr.hash42.Model.Server no-undo

    get():

      if not HasValidServer then

      do:

        assign Server         = (new dotr.hash42.Model.Server()):FindUsingServerGUID(this-object:ServerGUID)

               HasValidServer = yes.

      end.

      return Server.

    end get . private set .

I can then say elsewhere

if HasValidServer then delete object Server.

which doesn't have the same effect as

if valid-object(Server) then delete object Server.

as the above will always create a Server instance if we are lazy-loading (ie not creating the server instance until it is actually used)

Posted by gus on 28-Jun-2012 09:06

Code. Looping through all the objects in the entire universe (well ok, it's just the application).

Posted by JamesDev on 13-Jul-2012 20:53

Do you need to explicitly delete the object?

If not, you could call a method to assign the property to ? and let the garbage collector clean it up (assuming there are no other references to the object).

Posted by jmls on 14-Jul-2012 04:25

that would probably work for me. Will have to try it out and let you know.

Thanks !

This thread is closed