IBM®
Skip to main content
    Country/region select      Terms of use
 
 
   
     Home      Products      Services & solutions      Support & downloads      My account     

developerWorks  >  Lotus  >  Forums & community  >  Best Practice Makes Perfect

Best Practice Makes Perfect

A collaboration with Domino developers about how to do it and how to get it right in Domino

I've been doing a lot of programming in LotusScript recently using linked lists, and refining my technique.  This might be old news to some of you but I thought I'd mention it.  And what I'm saying here in part applies specifically to LotusScript, but in part to any language that does reference counting.

LotusScript memory management is not perfect, and I've encountered situations where it gets hung up when deallocating memory, particularly when there are object references that go across script libraries (a class in Library A contains a reference to an object whose class is declared in Library B). The more you deallocate objects yourself with a Delete statement, the better your chances of not having a problem.

Of particular interest are doubly-linked lists, where you have a "previous" and a "next" pointer in each node, and somewhere else you have a "first" pointer to identify the start of the list. As in the example shown here, you have an Ocean object containing the location of a list of Fish.

Class Fish
     
' some properties of fish omitted here
      Public Prev As Fish
      Public Next As Fish
End Class

Class Ocean
      FirstFish As Fish
       ...
End Class

Sub Initialize
      Dim pedantic As New Ocean
      pedantic.AddFish
' method not shown
      pedantic.AddFish
...

In the example data depicted on the right, the Ocean object has a list of two Fishes. The Prev pointer of the first one points to Nothing, as does the Next pointer of the second one. This is great; we can create as long a list of Fish objects as we like, insert them in between existing elements of the list without having to shift other things around like we would with an array, search backwards and forwards until we find just the right fish.

LotusScript automatically keeps a reference counter to objects so that it knows when they are no longer referenced anywhere and it can delete them. The Ocean object pedantic is referred to once (in this example) because you declared it as a stack variable in the Initialize subroutine of an agent. The first Fish is referenced twice -- once by pedantic's FirstFish pointer, and once by the Prev pointer of the second Fish.  The second Fish is referenced once, by the Next pointer of the first fish.

The trouble comes when we're all done. If we let the default memory management handle things, when the Initialize sub terminates the last reference to the Ocean object, pedantic, goes away, so that memory is deleted. Then LotusScript looks around for any other objects whose reference counters have dropped to zero, because they can also be deallocated. But there are none. The two Fish objects refer to each other, so neither one can be deleted first -- their reference counters will never drop to zero.

If it were a singly linked list, things would be different. When the Ocean object went away, the first Fish would have no more references, and so it would get deleted, then the next Fish would be an orphan, and pop, pop, pop, all the way down the chain. At least in theory; as I mentioned, LotusScript sometimes manages to screw things up somehow. I wrote an SPR about it.

But anyway, in this situation, with the doubly linked list, two Fish objects cling desperately to each other to preserve their existence as all around them whirls off into chaos. Which of course, is not what we want.

That's why one must be aggressive about deallocating the objects when their parent container is freed. So for instance, in this case we could add a destructor to the Ocean class:

Sub Delete
      Dim aFish As Fish
      Do Until FirstFish Is Nothing
              Set aFish = FirstFish
              Set FirstFish = FirstFish.Next
              Delete aFish
      Loop
End Sub

To make things easier, a separate function, or a method of the Fish class, could do this list deallocation.  In a recent OpenNTF project I published, I took this approach, writing a function that returned a Fish object to the caller (essentially) and then expecting the caller to call my subroutine to deallocate the list when they were done with it.

I should've thought harder about that; then I would've realized that expecting a programmer to remember to call a special function at the end is doomed to failure. Of course they'll forget sometimes (I forgot once, myself), or they'll be debugging it and stop early, and then there's a little school of Fish that never go away. So in my next version of that tool (not yet published) my function wouldn't return a Fish, but a new class, FishList, which like the Ocean class above, has a FirstFish pointer and a Delete method to make sure all the Fish objects die, die, die. And it can contain other useful functions, like inserting into the list, sorting, whatever. In fact, to avoid duplication of code, if another object (like Ocean) also needs a list of Fish, it should have FishList as a property instead of a pointer to the first Fish in the list. That's an extra object you wouldn't otherwise need, but it's worth it to avoid having to track every exit point to make sure you've called all the right memory-freeing functions.

So -- like I said -- might have been a refresher for some of you, but I hope you found it useful.

Andre Guirard | 28 October 2009 07:00:00 AM ET | Man-Cave, Plymouth, MN, USA | Comments (3)

Search this blog 

Disclaimer 

    About IBM Privacy Contact