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

Users of other object-oriented languages may be accustomed to registering "listeners" (for the Java crowd) or "callbacks" (for C/C++). These are functions or classes that you can pass in to other functions or classes; when certain parts of the process are reached, your routine will be called. For an example of what I'm talking about, see the NotesTimer class; you use the On Event statement to register your own routine to be called when the timer triggers.

Problem is, there's no facility in LotusScript for creating your own event types, so you can't extend this system to your own classes. There's also not a way in LotusScript to get a handle to a subroutine, so you can't pass your subroutine to another subroutine as an argument.

What you can do, however, is define a class of your own with certain methods that the called code expects to find, and put your own code in those methods. Then, create an object of that class, and pass the object to something you're making a call to. When it gets to the appropriate point in its code, whatever you called invokes a method of the object you passed it (assuming that the method actually exists and takes the arguments it's expected to).

For a real-life example, consider the code I posted yesterday to sort fields in a table. This works great, except that it makes certain assumptions about how field names are formatted. It works in cases where the fieldnames in the table are of the form name?#, where ? is some dividing character, like underscore, and # is the row number starting with 1. Of course, Murphy's law says that when you have a restriction like that, the very first developer who tries to make use of it has an incompatible form -- they start numbering their rows at zero, or the row number doesn't come at the end, or (as occurred) both.

We could do little things to make this more flexible -- have them pass us a macro formula, or a LotusScript expression we would pass to Evaluate to calculate the field name, for instance -- but but that's a little slow, and not very powerful if you wanted to do more than just calculate a simple value. Worst of all, it doesn't demonstrate the technique I wanted to demonstrate.

So, with the new code (attached), if you want to use the table sorter, and you have fieldnames of a form other than name_#, you (the caller) have to supply a subroutine that calculates the name. You do this by creating a new class -- call it what you like -- with a method named Mangle, defined as follows:

Class ClassName
      Function Mangle(fname$, Byval row%) As String

' insert your custom code here
      End Function

End Class

For example, in the specific case, the developer has columns as follows: cat#, lot#, cst#, vb#_0, vb#_1, vb#_2, vb#_3, vb#_4,  vb#_5, vb#_6,  vb#_7,  vb#_8,  vb#_9, Desc#,  h#_0, h#_1, gp#, PercentIncrease#, pr#_0 where # is the zero-based row number.

So his callback class could be:

Class FNMSubZBase
      Function Mangle(fname$, Byval row%) As String

              Mangle = Replace(fname, "#", Cstr(row-1))

      End Function

End Class

and he could call the sorting function as follows:

Dim myMangle As New FNMSubZBase
Call SortATable(uidoc, "cat#, lot#, cst#, vb#_0, vb#_1, vb#_2, vb#_3, vb#_4,  vb#_5, vb#_6,  vb#_7,  vb#_8,  vb#_9, Desc#,  h#_0, h#_1, gp#, PercentIncrease#, pr#_0", "cat#", 10, myMangle, True)

At the receiving end, the myMangle argument is declared as Variant, because of course we have no idea what its actual datatype might be. Now, the code that does the sorting takes the myMangle argument, stores it, and when it needs to calculate the name of a field, calls its Mangle method:

For i = 1 To m_rows
      Set record = New sortingRecord(Ubound(m_keys), Ubound(m_fields))

      For k = 0 To Ubound(m_keys)

              fname = m_callback.Mangle(m_keys(k), i)

              record.keys(k) = doc.GetItemValue(fname)(0)

One problem with this approach is that if you mess up and pass in a class that doesn't have the right methods and arguments, you don't know about it until you run the code and it fails. Java handles this more gracefully, by letting you define an "interface" -- a class definition without any of the methods -- that you can use as a model for your callback class. The compiler confirms that your class has in fact implemented all the methods that are expected by the code you're calling. I can't think of any way to do this in LotusScript -- maybe one of you folks can.

Andre Guirard | 5 August 2008 10:30:00 PM ET | Home, Plymouth, MN, USA | Comments (6)

Search this blog 


    About IBM Privacy Contact