OO & Session Cleanup

Posted by Tim Kuehn on 05-Dec-2006 17:04

I'm going through the Open Edge Getting Started:OO Programming docs, and found on page 2-37 the following:

If an object is not explicitly deleted, it remains instantiated throughout the entire Progress session. When the client session is shut down, Progress deletes all remaining class instances and frees all resources associated with them. However, the destructor for all of these objects is not executed when the session ends and the application exits.

Why would an object's destructor not be run when cleaning up a session with hanging class objects lurking around?

All Replies

Posted by Admin on 06-Dec-2006 01:52

Why would an object's destructor not be run

when cleaning up a session with hanging class objects

lurking around?

It's easier to shutdown the application this way, since there will be no user code executing anymore... I think the only requirement here is to release all memory and resources when the prowin32.exe ends.

Anyway, you should never rely on destructor-code to rollback something you have started! The question is: why don't you delete those objects while you can? There are several practical reasons in my opinion:

- when transferring ownership of an object, it's not clear anymore who should destruct the object (when is it safe to delete it for instance)

- some objects are static and should remain in memory during the session

The only sensible thing to do is the introduction of a garbage collector in the ABL and let it handle object destruction (http://en.wikipedia.org/wiki/Garbage_collection_(computer_science) )

Posted by Tim Kuehn on 06-Dec-2006 07:43

Anyway, you should never rely on destructor-code to rollback something you have started!

I'm thinking more of committing things and cleaning up stuff the object's logged over it's lifetime.

The destructor's there for a reason, and should be run when the object's deleted even at the end of the session and the application hasn't deleted it.

The only sensible thing to do is the introduction of a garbage collector in the ABL and let it handle object destruction

I implemented something like that with my procedure manager, and it works very well.

I may have to do something similar for objects...

Posted by Phillip Magnay on 06-Dec-2006 08:27

The destructor's there for a reason, and should be

run when the object's deleted even at the end of the

session and the application hasn't deleted it.

But you're expecting the wrong reason. A destructor is a method that is run when an object is explicitly destroyed. This is the case in C++ and is the case OpenEdge ABL. Most C++ environments and certainly the OpenEdge ABL do not use an automated garbage collector dedicated to the purpose of cleaning up dereferenced objects. In C++, a developer typically had to develop their own resource management/ garbage collection mechanism.

Now other languages such as C# and Java which run on virtual machines with automated garbage collection, do not really have destructors. Instead, the programmer is able to define finalizer methods which will be run by the respective VM when the garbage collector tries to clean up a dereferenced object. These finalized methods are never (or should never) be explicitly called by other code. They should be utilized in a way that assumes that the GC will call them without assuming how or when.

Anyway, you should never rely on destructor-code

to rollback something you have started!

I'm thinking more of committing things and cleaning

up stuff the object's logged over it's lifetime.

Strongly advise against doing anything like this. Use destructors to free up resources but do not use them to commit or roll-forward transactions. Same advice goes for finalizer methods.

The only sensible thing to do is the introduction

of a garbage collector in the ABL and let it handle

object destruction

I implemented something like that with my procedure

manager, and it works very well.

I may have to do something similar for objects...

As I mentioned above, some object/resource management mechanism that takes care of object clean up will be necessary.

Phil

Posted by Tim Kuehn on 06-Dec-2006 08:46

Strongly advise against doing anything like this. Use destructors to free up resources but do not use them to commit or roll-forward transactions.

Why?

Which is easier to do:

objname:do-something().

delete object objhandle.

or

delete object objhandle.

At least with the clean-up code on the delete of the object, I know it'll do whatever needs to be done. This would propagate down to any delegate class objects as well. If not, then any object manager would need to know (a) there's a cleanup method that has to be called first, (b) call that method (can a method be called dynamically yet?), then (c) delete the object.

We know an object's destructor will be run when it's deleted, it's consistent, it will always be done, hence it's the safest place to put cleanup code.

Posted by Tim Kuehn on 06-Dec-2006 08:55

On the other hand, can an object delete itself? If so, then this construct would be possible:

objname:delete-self().

And the delete-self method would do a bunch of stuff, and then

delete object this-object.

which would call the destructor, etc.

That could be made to work..

Posted by Phillip Magnay on 06-Dec-2006 11:17

Strongly advise against doing anything like this.

Why?

Which is easier to do:

objname:do-something().

delete object objhandle.

or

delete object objhandle.

At least with the clean-up code on the delete of the

object, I know it'll do whatever needs to be done.

This would propagate down to any delegate class

objects as well. If not, then any object manager

would need to know (a) there's a cleanup method that

has to be called first, (b) call that method (can a

method be called dynamically yet?), then (c) delete

the object.

We know an object's destructor will be run when it's

deleted, it's consistent, it will always be done,

hence it's the safest place to put cleanup code.

Sorry. I may have confused you. What I wanted to emphasize as per my previous post was: In other words, cleaning-up resources is fine but advise against commiting or roll-forwarding/back anything... for the very reason that destructors will not be run by default when a session ends either gracefully or otherwise.

Posted by Thomas Mercer-Hursh on 06-Dec-2006 11:44

Using a

factory is probably going to be essential.

Posted by Thomas Mercer-Hursh on 06-Dec-2006 11:49

Tim, I'm with Phil on this one. Whatever the purpose of the object, its life and impact should be controlled by its regular methods.

If for no other reason, just think in terms of how intuitive the code is. If I say:

myObject:saveChanges()

or

myObject:finshProcessing()

it is really clear what is going on, but if I say

delete object myObject

there is no indication that I expect meaningful processing to occur.

Posted by Tim Kuehn on 06-Dec-2006 11:59

Tim, I'm with Phil on this one. Whatever the purpose of the object, its life and impact should be controlled by its regular methods.

I have no quibble with explicit method calls to 'finish' an object's work.

I'm thinking that

DELETE OBJECT objhandle.

is actually a bad way to do things, one should do instead

objname:cleanup-and-delete-self().

and have the object delete itself when it's done.

Having said that, the language has to deal with programmers of a varying level of expertise, and automatically running the destructor code when the object's deleted is the safest course to follow. I'm just thinking the run-time client should do the same thing when it closes down. If things don't shut down cleanly, the resulting chaos may force the developer to clean their code up.

Too bad deleting procedure instances doesn't do the same thing.

Posted by Thomas Mercer-Hursh on 06-Dec-2006 12:07

Myself, I don't have any problem with the delete object syntax, especially since the destructor is often not even needed unless there are some specific resources to destroy. Why force us to write and call an explicit destructor when all it is going to contain is delete myself?

And, given that its only job should be to free up resources, I'm not so sure that I see the importance of running it at a time when all resources are going to be freed anyway.

Posted by Tim Kuehn on 06-Dec-2006 12:16

If one object creates other objects, then those objects have to be destroyed as well. I can think of other case where one would need to do other "cleanup" work when an object goes away.

Most of the time destructors probably aren't going to be needed, but it's not 100% of the time.

Posted by Thomas Mercer-Hursh on 06-Dec-2006 12:47

I'm not saying that I don't see a need for a destructor ... clearly there are cases where an object creates resources which should be released before the object is destroyed. All I was suggesting was that at the point when the session is ending and all resources are going to be released anyway, that I'm not sure that there is a benefit to doing so in some orderly process of running destructors. Indeed, it would clearly slow down the close and would raise some interesting issues. E.g., Object A creates Object B and has a delete object B in its destructor ... and what happens if the session ending runs the destructor in B prior to A?

Which said, if we ever get garbage collection, the destructors should clearly be run then.

Posted by Tim Kuehn on 06-Dec-2006 13:01

All I was suggesting was that at the point when the session is ending and all resources are going to be released anyway, that I'm not sure that there is a benefit to doing so in some orderly process of running destructors.

I'm thinking it's a bit inconsistent to run the destructor when an object's deleted, but not when the session closes which causes an implicit deletion.

Indeed, it would clearly slow down the close and would raise some interesting issues. E.g., Object A creates Object B and has a delete object B in its destructor ... and what happens if the session ending runs the destructor in B prior to A?

First, it would slow things down only if the objects were left undeleted.

Second, if I'm reading the docs right, the client knows the order that it creates the objects. Ergo, one can choose to delete objects FIFO order, or in reverse FIFO order. Then again, my procedure manager traverses every procedure instance tree to figure out which ones are going away, and deletes the deepest instances in the instantiation stack first and works it's way to the top.

Posted by Thomas Mercer-Hursh on 06-Dec-2006 13:26

Well, yes, but

then if they have already been deleted, the issue is moot. I think

the point here is that we know that the right thing to do is to

systematically delete everything through the code. What happens

otherwise is the question. If the design is correct, then either we

are going to have normal shutdown and there will be nothing left to

delete or we are going to have abnormal shutdown, in which case we

probably shouldn't be counting on orderly processing. Given that we

have talked you out of putting commit logic into the destructor,

what actual advantage would there be to running destructors at

session close rather than just sweeping up the lot all at once?

Posted by Tim Kuehn on 06-Dec-2006 13:45

Given that we have talked you out of putting commit logic into the destructor,

That's a big "given", and a premise I still disagree with.

what actual advantage would there be to running destructors at session close rather than just sweeping up the lot all at once?

First, the behavior's inconsistent with what happens during the DELETE OBJECT statement.

Second, there are cases where it may be desirable to automatically fire off object destructors, particularly in cases where a developer's implementing behavior that modifies an existing program that you don't have the source to (ala ProTaylor or a repository-driven UI validation / help assist system), and can't start / stop it's own transactions. If the target program does a "quit" - you have no way to log the data you've collected because the objects just go away rather than fire their destructors so the accumulated data can be logged.

There's no effective object instance management support in the language right now. All I've seen in the docs so far is that the developer has to manually track all object instances and then clean them up afterwards, just like with PP/SP instances. That's a pretty messy task, and until an object management system is developed that's reasonably easy to use and transparent to the developer, I'm sure the full power of the OOABL won't be realized, and there'll be objects being left "in the wild" during shutdown due to some (understandable) oversight in not deleting the objects in code.

If their destructors were fired at session closedown, it would be possible to find those instances and do something about them. (A PSC TS engineer told me there's a way to track memory leaks in the language already, but I don't know if it applies to class instances or not).

Interestingly enough, the CLASS statement has a USE-WIDGET-POOL to create a class-scoped WP instance that all dynamically created objects will reside in, which would help with objects that are only supposed to be used in the class instance. It can't be used where one class makes objects that are used both internally and externally.

What a messy web we weave...

Posted by Thomas Mercer-Hursh on 06-Dec-2006 14:17

One might have said the same about PPs and SPs and

yet they seem to have gotten around pretty well. Though, I

certainly agree that the more framework we can get on the table and

the more guidance and example that can be provided, the more likely

it is that OO features will be used and used properly. Without it,

there is likely to be a lot of ugly stuff.

Posted by Tim Kuehn on 06-Dec-2006 14:39

It seems to me to be pretty clear that the purpose of a destructor is cleanup only, not any kind of commit or role-back or whatever.

In an application, that can be considered cleanup.

Moreover, as I believe Phil has outlined, this is actually consistent with other OO languages so your urge to turn destructor into some kind of "finally" is out of step with existing practice.

If that's the case, then the docs need to be more clear about that.

I think this is a matter of interpretation or misinterpretation.

That's possible. Procedure, buffer, query, and other object instances don't fire off any implicit action when they're deleted, so when a session closes down, the behavior is consistent - the object's just 'go away' just like if they were deleted 'manually.'

But deleting class object instances implicitly fires off their destructor. Ergo, a session shutdown should do the same.

One might have said the same about PPs and SPs and yet they seem to have gotten around pretty well.

I won't quibble that they have, but they've been either a pain to work with, or haven't been utilized to their full potential, which is what I said.

Though, I certainly agree that the more framework we can get on the table and the more guidance and example that can be provided, the more likely it is that OO features will be used and used properly. Without it, there is likely to be a lot of ugly stuff.

Given the varied background of ABL developer's I've seen in the past, I suspect there'll be more than less of the ugly stuff if good, easy-to-use frameworks or constructs aren't provided.

Posted by Thomas Mercer-Hursh on 06-Dec-2006 15:21

Even more to the point, perhaps, without the

framework, guidance, and some really active cheerleading, use of

the OO constructs is likely to be limited.

Posted by Tim Kuehn on 06-Dec-2006 15:31

More clear docs is always a good thing, but I can see where Phil would argue that this was common OO practice and therefore not necessarily something that needs to be spelled out at length.

Come on Tom (and/or Phil if he actually agrees with this), you should know better.

The audience for these docs are ABL, not OO developers, so they most likely as not have little exposure to how the rest of the OO world does things. If these kinds of expectations aren't spelled out, then there's no cause to cite how the "rest of the OO world" does things as reasons for existing ABL developers not to do something.

this shutdown is abnormal and it is wildly optimistic to think that it is going to do all these neat and tidy things.

All bets are off with abnormal shutdowns, which isn't part fo my discussion.

It isn't going through a list of procedures, widgets, temp-tables, etc. and deleting them one by one, it just yanks all the memory back and flushes out all the tables.

Flushing out all the tables? Sounds like orderly behavior to me...why not just delete them and be done with it, just like everything else?

Posted by Thomas Mercer-Hursh on 06-Dec-2006 15:52

Let's just say that, compared to things like the big example in the middle of GSOOP, this is not one of my biggest issues about the documentation.

One of my concerns, in fact, is that only those already familiar with OO will be the ones to try to use it in ABL. That would greatly limit its use.

Probably a poor choice of words. I certainly don't mean any ABL tables. I just mean releasing all of its own internal space back to the OS.

Posted by Tim Kuehn on 06-Dec-2006 15:59

Let's just say that, compared to things like the big example in the middle of GSOOP, this is not one of my biggest issues about the documentation.

I agree - I just raised this as an issue since I'm going through the docs anyway.

One of my concerns, in fact, is that only those already familiar with OO will be the ones to try to use it in ABL. That would greatly limit its use.

OO provides a way to develop an extensive framework of utilities and tools, which could encourage developers to stick their toes in the OO waters.

Personally, I'm finding the new stuff a bit more complicated than what I've run into before, but not insurmountable. At least I can see how to do things and come up with my own test/example code this time!

But, with a normal, planned shutdown, you, the application developer, will have already cleaned up everything and the issue is moot!

In a perfect world that would be correct.

We don't live in a perfect world though.

Posted by Thomas Mercer-Hursh on 06-Dec-2006 16:23

My sympathies!

You

aren't suggesting that programmers make mistakes, are you? Well, if

they do, then they should pay!

Posted by Tim Kuehn on 06-Dec-2006 16:27

You aren't suggesting that programmers make mistakes, are you?

Well, if they do, then they should pay!

Yes they should - that's a good part of how I make my living.

Posted by Tim Kuehn on 06-Dec-2006 16:39

My sympathies! :)

Indeed - check out this quote from page 5-11 of the OO Getting Started docs:

The examples in the following sections compare the use of classes using inheritance with the use of procedures and super procedures. The same application is implemented using classes and procedures. A summary comparison follows the listing of all classes and procedures, with commented numbers in the code matched to comments in the summary comparison. Note: These classes are not separately available online, but only in this manual.

Emphasis mine...

I could probably cut 'n' paste from the PDFs into program files - but I shouldn't have to do that in the first place...

Posted by Thomas Mercer-Hursh on 06-Dec-2006 16:40

My wife read me an F. Lee Bailey quote last night:

"The guilty never escaped unscathed.

My fees are sufficient punishment for anyone."

Posted by Tim Kuehn on 06-Dec-2006 16:47

My wife read me an F. Lee Bailey quote last night:

"The guilty never escaped unscathed.

My fees are sufficient punishment for anyone."

Bound to be a classic! And coming from him, the fees would be breath-taking indeed...

Posted by Admin on 07-Dec-2006 02:42

On the other hand, can an object delete itself? If

so, then this construct would be possible:

objname:delete-self().

And the delete-self method would do a bunch of stuff,

and then

delete object this-object.

which would call the destructor, etc.

That could be made to work..

In .Net there is the IDisposable interface, which allows you to scope an object to a "using"-statement (the "using" here is not the "using" in ABL to introduce a namespace). Example:

using (StockAllocator allocator = new StockAllocator())

{

allocator.Allocate("MARS", 1000);

} // at this stage the Dispose() method will be called, just before the object is deleted

This pattern translates to:

StockAllocator allocator = null;

try

{

allocator = new StockAllocator();

allocator.Allocate("MARS", 1000);

}

finally

{

allocator.Dispose();

} // allocator gets destructed

For short lived objects this is a nice way of scoping an object. In this case it would be rather frustrating when the runtime wouldn't call the "Dispose", since that's part of the contract.

There are of course objects that have a long lasting lifetime. In those cases you can't use the "using"-phrase and it's hard to figure out when the object should go. And I agree with Tim: it will be very easy in the ABL to make mistakes about this and never delete certain class instances (this problem applies to dynamic temp-tables/datasets as well: as soon as you start mixing handles with static definitions in method calls, it will be very hard to track ownership down). But on application shutdown, all memory will be reclaimed, objects will be deleted, so no worries there (unless the runtime makes a mistake and won't release memory). You will only have a 4GL-memory leak when you won't reclaim instantiated ABL class instances during the session, so your application will slow down.

In a garbage collected environment there are different sweep-algorithms. In a mark-and-sweep algorithm, used by .Net, the runtime checks for unreachable objects, marks them for destruction, and deletes the marked objects. In this approach the order of destruction is unpredictable and therefor you can't rely on anything in the destructor method. You should only free so called "unmanaged resources". You shouldn't even delete other "managed objects", since that will be taken care of by the garbage collector.

So you probably use the destructor code as a last resort, else you can't reliably tell when your object's lifetime ends, right? Perhaps all you need is an "application shutdown event", something similar to the hooks an AppServer provides when the session ends...

Posted by Phillip Magnay on 07-Dec-2006 05:32

More clear docs is always a good thing, but I can

see where Phil would argue that this was common OO

practice and therefore not necessarily something that

needs to be spelled out at length.

Come on Tom (and/or Phil if he actually agrees with

this), you should know better.

It would be quite perilous for me to make such an argument.

The audience for these docs are ABL, not OO

developers, so they most likely as not have little

exposure to how the rest of the OO world does things.

If these kinds of expectations aren't spelled out,

then there's no cause to cite how the "rest of the OO

world" does things as reasons for existing ABL

developers not to do something.

I agree 100%. That said, this is an long-standing debate with OO developers which the OpenEdge community will eventually need to grasp. An OpenEdge session follows the C++ standard (not .NET) where destructors will only be run when objects are explicitly destroyed. There is no automated garbage collection or any other underlying mechanism to force destructors or finalizer methods to run when a session is shutdown. Therefore, destructors are not a reliable place to put code that must absolutely 100% be run.

Posted by Tim Kuehn on 07-Dec-2006 07:44

Therefore, destructors are not

a reliable place to put code that must absolutely

100% be run.

Could this explanation be added to the docs then? I think this is rather important.

Posted by Thomas Mercer-Hursh on 07-Dec-2006 11:07

While the using syntax might be a handy shorthand ... although I can't say I like the choice of verbs ... I don't see management of short-lived objects as much of an issue. With a short-lived object, one merely needs to delete it at the end of the block in which it is needed or, if there are multiple exit points from the block, then below the block. The real issue with managing the object lifeline comes in objects that wander about from place to place (e.g., layer to layer) and/or persist for long periods of time. Worst, perhaps, are service objects which one might not want to scope to the entire session, but it can be vague when one wants to get rid of it. Certainly, an object factory is part of the solution. Another technique can be found here http://www.oehive.org/PseudoSingleton where it is shown how to get a single object to serve multiple "customers" and yet disappear when the last of those customers is done.

Posted by Phillip Magnay on 07-Dec-2006 16:37

Therefore, destructors are not

a reliable place to put code that must absolutely

100% be run.

Could this explanation be added to the docs then? I

think this is rather important.

I have forwarded this thread to the relevant tech writer in OpenEdge documentation.

Posted by Admin on 07-Dec-2006 22:10

Indeed - check out this quote from page 5-11 of the

OO Getting Started docs:

>...

Note: These classes are not separately available

online, but only in this manual.

Emphasis mine...

Hello,

I expect that our 10.1B version is a big improvement over the 10.1A doc in this respect. We are delivering the sample classes on-line as part of the Documentation and Samples CD. These classes have also been cleaned up quite a bit, and they do compile and run as a single application, and as expected. As you will read from the new introduction to these samples, this code is not intended to represent best practices, but to illustrate the use of individual features. Still, we tried to make basic improvements that hopefully make these samples far more practical and useful than they were in 10.1A. We are not done with this. We will be working to improve our code examples going forward, and all your feedback, such as Thomas has already provided (thank you!), is more than welcome.

Also, in addition to new writing to document the new 10.1B features, many sections of the GSOOP book have been revised or rewritten for clarity, consistency, and completeness, which we hope will benefit the ABL programmer who is new to OO.

Oh, and BTW, in this book only we are trying out a new hypertext technique in 10.1B that allows you to link directly to reference pages in the "ABL Reference." It will only work with the complete PDF doc set installed on your system, and I believe also in the HTML version of the complete doc set (though I have not tried it yet). Just click on any textual references to statement and other reference entries that are link blue. I'd be curious to know if this is helpful.

- Dan

Posted by Admin on 07-Dec-2006 22:46

Therefore, destructors are not

a reliable place to put code that must absolutely

100% be run.

Could this explanation be added to the docs then? I

think this is rather important.

We do, as you know, state that the destructor is not run for instantiated classes when the ABL session ends. Perhaps, I can amend this to say "when the session ends normally or abnormally" and add: "therefore, do not include code in a destructor that you want to run reliably 100% of the time."

Anyway, I'll make a note about this for the next go round.

- Dan

Posted by Admin on 08-Dec-2006 08:26

Oh, and BTW, in this book only we are trying out a

new hypertext technique in 10.1B that allows you to

link directly to reference pages in the "ABL

Reference."

That's great! Will it also be possible to use the "back" button and go back to the previous location?

Posted by Admin on 08-Dec-2006 08:28

The real issue with managing the object lifeline comes in

objects that wander about from place to place

I'm glad you repeat what I wrote and that you agree on this one....

Posted by Admin on 08-Dec-2006 10:45

That's great! Will it also be possible to use the

"back" button and go back to the previous location?

Yes, precisely. Not every reference is linked, but I tried to do at least the first reference per section and within a page or two of each link, as well.

There is a slight bug in Chapter 1, where a few multi-word references are only hot on the first word. These links were created a little differently and I forgot a step without realizing it later when the new technique became available. Hope it's not too much of a bother. Will fix next time around.

- Dan

Posted by Admin on 08-Dec-2006 12:27

Yes, precisely. Not every reference is linked, but I

tried to do at least the first reference per section

and within a page or two of each link, as well.

A small sidestep in this thread about "OO & Session Cleanup": have you tried the HTML-version of the online documentation? Once it has been loaded it's great, but man, it takes forever before you see the contents pane... This link for instance http://documentation.progress.com/output/OpenEdge101a/wwhelp/wwhimpl/java/html/wwhelp.htm?href=dvref/dvref-01-1.html.

Personally I think this version is better readable than the PDF-version...

Posted by Thomas Mercer-Hursh on 08-Dec-2006 12:34

That is a rather significant startup delay, isn't it!

Posted by Admin on 08-Dec-2006 15:51

... This link for instance

http://documentation.progress.com/output/OpenEdge101a

wwhelp/wwhimpl/java/html/wwhelp.htm?href=dvref/dvref-0

1-1.html.

It took me about 20 seconds to get the navigation tree to open over a VPN. However, it took 2 minutes to do the same while I was downloading the entire HTML doc set.

Were you downloading anything at the same time?

Personally I think this version is better readable

than the PDF-version...

Interesting. Some folks prefer the PDF because you can scroll through it more easily, it has a great global search (with Acrobat Reader 7.0), and it prints well. However, I can see the appeal of the HTML, which presents each section as a separate page, and uses a nice display font.

- Dan

Message was edited by:

Daniel Rose

Posted by Thomas Mercer-Hursh on 08-Dec-2006 16:03

For me, over a 4-5Mbs line, it is a little over 20 seconds for the navigation panel to show, but another 15+ seconds before it quits flickering away and is ready to pay attention to me. Not a huge time in the overall scope of things, but long if one is just expecting a web page to come up.

Posted by Tim Kuehn on 14-Dec-2006 18:00

So you probably use the destructor code as a last resort, else you can't reliably tell when your object's lifetime ends, right? Perhaps all you need is an "application shutdown event", something similar to the hooks an AppServer provides when the session ends...

This would be a perfect use for PUB / SUB - but that's verboten with classes...

Posted by Tim Kuehn on 14-Dec-2006 18:04

I expect that our 10.1B version is a big improvement over the 10.1A doc in this respect. We are delivering the sample classes on-line as part of the Documentation and Samples CD. These classes have also been cleaned up quite a bit, and they do compile and run as a single application, and as expected.

Great!

As you will read from the new introduction to these samples, this code is not intended to represent best practices, but to illustrate the use of individual

features. Still, we tried to make basic improvements that hopefully make these samples far more practical and useful than they were in 10.1A. We are not done

with this. We will be working to improve our code examples going forward, and all your feedback, such as Thomas has already provided (thank you!), is more than welcome.

Bwahaha

Also, in addition to new writing to document the new 10.1B features, many sections of the GSOOP book have been revised or rewritten for clarity, consistency, and completeness, which we hope will benefit the ABL programmer who is new to OO.

Coolness. Are all the "you can"s gone?

Will there be a beta version I can check out?

Oh, and BTW, in this book only we are trying out a new hypertext technique in 10.1B that allows you to link directly to reference pages in the "ABL Reference." It will only work with the complete PDF doc set installed on your system, and I believe also in the HTML version of the complete doc set (though I have not tried it yet). Just click on any textual references to statement and other reference entries that are link blue. I'd be curious to know if this is helpful.

Is this different from the linking I thought I was already using in the PDF docs? Or is it taken to a more detailed level?

Posted by Thomas Mercer-Hursh on 14-Dec-2006 18:17

But, if you are in enough control of the shutdown to issue an "application shutdown event", then you are also in enough control to delete any remaining objects.

To me, it seems like we have a couple of basic contrasts here.

The first is based on whether or not there is automatic garbage collection. There are some obvious advantages to having it, but in some ways it is also an excuse to be sloppy. We don't have it so we don't really have the choice -- we need to manage object lifetimes.

And, if they are managed and we are dealing with an orderly delete, then I think there are strong arguments against putting any code in a destructor except code that cleans up artifacts of the object. It would be nice to have that more automatic too, like the widget-pool concept of parenting certain resources to the object so that they are automatically cleaned up when the object goes away. Again, we don't have it and so need to put housekeeping stuff in the destructor ... but it is pretty obvious stuff. I find it difficult to see that it is a good idea for an object to do something transactional at death because there is so much risk associated with it. There is no way to guarantee that code is absolutely going to run.

And, if we aren't dealing with an orderly delete, then all bets are off. The only semi-clean thing I can think of is a multi-threaded environment where one thread dies without killing off the rest of them, but as long as this releases the memory being used by the thread, there is no need to pretend that all the destructors in that thread or going to be run ... it is just going to all go away.

Posted by Tim Kuehn on 15-Dec-2006 08:23

But, if you are in enough control of the shutdown to issue an "application shutdown event", then you are also in enough control to delete any remaining objects.

Well, yes and no. I supposed you could walk the object tree and delete all the object handles until they were all gone.

One problem, though, is if they have delegate objects - particularly if their parent objects need them to do things before going away.

I have to wonder - is there a pattern to object instance hierarchies like there is with program call stacks that could be used to figure out which objects to delete first....

From my perspective, knowing which objects to delete first isn't an intuitively obvious exercise...

To me, it seems like we have a couple of basic contrasts here.

The first is based on whether or not there is automatic garbage collection. There are some obvious advantages to having it, but in some ways it is also an excuse to be sloppy. We don't have it so we don't really have the choice -- we need to manage object lifetimes.

Yes.

And, if they are managed and we are dealing with an orderly delete, then I think there are strong arguments against putting any code in a destructor except code that cleans up artifacts of the object. It would be nice to have that more automatic too, like the widget-pool concept of parenting certain resources to the object so that they are automatically cleaned up when the object goes away.

You can spec a class as having a widget-pool which'll automatically delete all of it's dynamic objects when the class instance is deleted. But that doesn't work when one or more of the created objects are in use elsewhere in the application.

Again, we don't have it and so need to put housekeeping stuff in the destructor ... but it is pretty obvious stuff. I find it difficult to see that it is a good idea for an object to do something transactional at death because there is so much risk associated with it. There is no way to guarantee that code is absolutely going to run.

Which is why that point has to be made painfully clear, because if it isn't, people will do that because they can. I'm thinking that a better way to handle 'finish your transaction and go away' stuff would be to have a method to do the cleanup, which ends with

delete object this-object.

And, if we aren't dealing with an orderly delete, then all bets are off.

Yes. I wasn't thinking about abnormal shutdowns in my comments, just cases where a given session was QUIT-ing in a normal, expected fashion.

Posted by Thomas Mercer-Hursh on 15-Dec-2006 12:07

For most objects, I would say this

was simply the destructor. What kind of work do you see hanging out

there pending which you would want triggered in association with

the destruction of the object? To me, it seems that the normal

expectation is that there is some block within which an object is

created and at the end of which it is deleted. During that block,

one has interactions with the object, one or more of which might be

transactional. But, the end of the transaction is conceptually

separate ... often physically separate ... from the "this is no

longer needed" decision.

Posted by Admin on 15-Dec-2006 12:56

The first is based on whether or not there is

automatic garbage collection. There are some obvious

advantages to having it, but in some ways it is also

an excuse to be sloppy. We don't have it so we don't

really have the choice -- we need to manage object

lifetimes.

Well the problem is that you might think you are managing the object's lifetime, but Progress might decide differently! Think about the strange code "DELETE OBJECT" you have to add at the end of a procedure when you return an OUTPUT TABLE-HANDLE parameter for instance:

http://progress.atgnow.com/esprogress/resultDisplay.do?gotoLink=155&docType=1006&contextId=21269%3A155.257&clusterName=CombinedCluster&contentId=3c0fc947-b148-4961-8ca1-a7cbfa5500b5&responseId=4f2e6f6f8c3365a4%3Ab60b93%3A10f8605b954%3A52d6&groupId=3&answerGroup=2&score=789&page=http%3A%2F%2Fprogress.atgnow.com%2Fesprogress%2Fdocs%2FSolutions%2FProgress%2FESERVER_P69199.xhtml&result=1&excerpt=Deleteofatemp-tableobjectisnotalwayspostponediftable-handleispassedasoutput+table-handle&resultType=5002#Goto155

"...

Symptoms:

Delete of a temp-table object is not always postponed if table-handle is passed as output table-handle

temp-table received as output table-handle parameter of another procedure

temp-table passed correctly if dataset is deleted in "main block" of called procedure

Dataset not passed if dataset is deleted in (sub)procedure called from called procedure where table-handle parameter is defined

Cause:

When passing a dynamic temp-table as an output table-handle parameter, a DELETE OBJECT statement should be executed for the temp-table before control is passed back to the calling procedure to prevent memory leaks.

If this is done, the actual delete of the temp-table will be postponed until it has actually been passed back to the calling procedure, but only if the DELETE OBJECT statement occurs in the same procedure as the OUTPUT TABLE-HANDLE parameter is defined.

If the called procedure in turn calls another procedure and this other procedure contains the DELETE OBJECT statement, the temp-table will be deleted immediately and will not be passed back to the original calling procedure.

Fixes:

Ensure temp-table is always deleted on the procedure level where the temp-table parameter is defined, and not on lower procedure levels.

..."

Right and where would that be

Posted by Thomas Mercer-Hursh on 15-Dec-2006 14:07

Would you remind replacing that URL with a tinyurl? It really goofs up the formatting of the thread and makes it hard to read.

Posted by Tim Kuehn on 28-Dec-2006 13:00

Interestingly enough, if a class does a RETURN ERROR from the constructor, that's an implict DELETE OBECT THIS-OBJECT. Would that run the failed-object's destructor?

From the 10.1B release notes:

Cannot use RETURN ERROR and DELETE OBJECT THIS-OBJECT in the same constructor.

RN#: 101B-00124

===============

If a constructor contains both a RETURN ERROR statement following a DELETE OBJECT THIS-OBJECT statement unexpected behavior may occur. RETURN ERROR accomplishes the same work as DELETE OBJECT THIS-OBJECT and additionally raises error on the NEW phrase. There is no benefit to using both statements and it is not recommended.

Posted by Thomas Mercer-Hursh on 28-Dec-2006 15:25

My guess is that it doesn't run the destructor because the object never gets fully instantiated, but, as you say, it is an interesting question. E.g., Suppose the constructor builds a temp-table and then fails...

Posted by Tim Kuehn on 28-Dec-2006 15:31

My guess is that it doesn't run the destructor because the object never gets fully instantiated, but, as you say, it is an interesting question. E.g., Suppose the constructor builds a temp-table and then fails...

or better yet creates some dynamic objects before it goes "boom".

This thread is closed