API
@-Formulas
JavaScript
LotusScript
Reg Exp
Web Design
Notes Client
XPages
 
Working With Custom Classes
Custom classes in LotusScript have been around as long as LotusScript (since version 4 of Notes), but with the introduction of Web Services in version 7, they are going to become more and more important. If you don't already know, when creating a web service you have to code things in a custom class when the web service is coded in LotusScript. This quick article tells you how I work with custom classes in LotusScript, which might be of some help to you.

First, I'll give a little background for those of you that have never worked with custom classes in LotusScript. All the custom class code goes into the (Declarations) area of your script library, agent, or web service. The class is bracketed by the Class and End Class statements. All the class methods, properties, and variables must be defined between those statements. Once a custom class is defined, it is used a lot like the standard Domino objects in LotusScript. You create an object by calling the New method, and get rid of it by calling the Delete method or letting LotusScript delete it automatically when the agent/web service terminates.

The biggest problem I have when working with custom classes is that there is no object navigator. You can't find out what methods/properties you have defined in your class, and (even if you already know the methods/properties) it is difficult to find the code you want to investigate. So, to make things easier on myself, I end up with subroutines and functions, just like a regular LotusScript agent, and almost every property or method simply calls one of my subroutines or functions.

This is much easier for me to support. The structure of the custom class is still in the (Declarations) area of the agent (or web service or script library), like it has to be, but only the structure. There is as little code as needs to be in that part of the code. The "meat" of the code is contained in subroutines and functions. I make sure to define all the subroutines and functions as Private in the code, so they are only relevant to the agent itself. This is especially important if your custom class is in a script library. There is no potential for duplicate names using private subroutines/functions. But the biggest advantage is that the standard object navigation now has all my properties and methods listed because they are subroutines/functions in the code.

Let's take a look at an example to explain the differences. The example I'll use comes straight from the Domino Developer help file, talking about custom classes in LotusScript. First, the "old" way, which comes straight from the help:

Class textObject
   ' Declare member variables.
   backGroundColor As Integer
   textColor As Integer
   contentString As String
   ' Define constructor sub.
   Sub New (bColor As Integer, tColor As Integer, _
   cString As String)
      backGroundColor% = bColor%
      textColor% = tColor%
      contentString$ = cString$
   End Sub
   ' Define destructor sub.
   Sub Delete
      Print "Deleting text object."
   End Sub
   ' Define a sub to invert background and text colors.
   Sub InvertColors
      Dim x As Integer, y As Integer
      x% = backGroundColor%
      y% = textColor%
      Me.backGroundColor% = y%
      Me.textColor% = x%
   End Sub
End Class

Now, how would I do this? Obviously, this is a bit extreme when there are only a couple of methods in the class. But when you start working with dozens of methods like there might be in a web service, I move things out to their own subroutines and functions. So here is my rewrite of the custom class:

Class textObject
   ' Declare member variables.
   Public backGroundColor As Integer
   Public textColor As Integer
   Public contentString As String
   ' Define constructor sub.
   Sub New (bColor As Integer, tColor As Integer, _
   cString As String)
      Call cNew(Me, bColor, tColor, cString)
   End Sub
   ' Define destructor sub.
   Sub Delete
      Print "Deleting text object."
   End Sub
   ' Define a sub to invert background and text colors.
   Sub InvertColors
      Call cInvertColors(Me)
   End Sub
End Class

The subroutines need to be defined still:

Private Sub cNew(obj As textObject, bColor As Integer, tColor As Integer, cString As String)
   obj.backGroundColor% = bColor%
   obj.textColor% = tColor%
   obj.contentString$ = cString$
End Sub

Private Sub cInvertColors(obj As textObject)
   Dim x As Integer, y As Integer
   x% = obj.backGroundColor%
   y% = obj.textColor%
   obj.backGroundColor% = y%
   obj.textColor% = x%
End Sub

As you can see, the code within the class itself is much smaller. So, when you have a bunch of methods inside your class, it is easier to see the methods. I call the subroutines the same name as the method except for the prefix of the letter "c" (for "class"). Some kind of prefix needs to be used because New cannot be a subroutine name. The subroutines are defined as Private, which means they are only relevant in the current context (the script library context).

In my object navigator, when looking at the script library, I can see "cNew" and "cInvertColors", so even without looking at the class definition, I know that those are either method or property names. I don't know the exact parameters, and I don't know exactly if they are a method or a property, but clicking on one gets me right to the code where I can find out.

The first parameter to every subroutine or function is the class object itself. That way I can do whatever manipulation I need on the object. Another choice is to define a global variable in the (Declarations) area and refer to the global variable in the subroutines and functions. But I'm not a fan of global variables in general, so I prefer my method.

The one big drawback to my method is that any variables within the class (like backGroundColor, textColor, and contentString) have to be defined as Public variables so the subroutines and functions can act on them. But this also means that anyone using the class can act on them as well, which may or may not be desired.

The only way to get around the public/private limitation is to pass the actual values to the functions, instead of passing the object itself. So, in the function that creates the object, I would need to pass in Me.backGroundColor. This is possible because variables, by default, are passed by reference. So updating the variable in the called subroutine updates the variable in the source class method. But it becomes difficult to understand the subroutine nature by looking at it - which ones are parameters, and which ones are private object variables that are being changed?

So, if I really need to have the variables be private to the class, then I don't end up using this method. But most of the time when creating custom classes it doesn't matter too much if the variables themselves are public or not, so I can go ahead and use my method of writing the script library. It makes things much easier, for me at least, to support down the road.

As always, keep in mind that there are multiple ways of doing just about everything in Notes. My way of writing custom classes may not be a good fit for you at all. But at least it gives you another way of thinking about how to organize the code in your custom class.