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 ?
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.
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 !
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.
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
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.
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...)
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.
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
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.
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
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
I thought that the factory was responsible for creating the foo instance ?
On 26 June 2012 16:36, Marko Rueterbories
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).
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.
That's disgusting.
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
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.
what's disgusting ? The code or the evil message ?
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)
Code. Looping through all the objects in the entire universe (well ok, it's just the application).
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).
that would probably work for me. Will have to try it out and let you know.
Thanks !