Coming back to object-oriented programming in LotusScript after a lengthy spell programming in only JavaScript was a bit of a shock: LotusScript isso restricted! Everything has to be declared and set up in rigid class hierarchies that can't be rejigged on the fly like you can in JavaScript (which has no real classes, of course ). and yet, with the judicious use of Lotus script's variant type, it's possible to free yourself from some of these more obvious restrictions.
Problem-class hierarchies
One restriction that's always bugged me about LotusScript Oo, is that the class libraries are a one-way door. class Library a can access the classes in class library B, or class library B can access teh classes in class library. but they can't both access each other's classes. to do so wocould set up an infinite loop of use statements, which the domino designer compiler does not allow.
Here's an example of this problem. I set up two classes in two separate LotusScript class libraries: the class carclass is in the carclasses Library and the class roadclass is in the roadclasses library. here's the code for the two classes:
'In carclasses LotusScript libary
Public class carclass
Private m_name as string
Private m_topspeedkmh as integer
Private m_weight as string
Sub new (n, k, W)
Me. m_name = N
Me. m_topspeedkmh = K
Me. m_weight = W
End sub
Public property get thename as string
Thename = me. m_name
End Property
Public property get topspeedkmh as integer
Topspeedkmh = me. m_topspeedkmh
End Property
Public property get weight as string
Weight = me. m_weight
End Property
End Class
'In roadclasses LotusScript Library
Public class roadclass
Private m_name as string
Private m_length as string
Private m_chargetype as string
Sub new (n, l, c)
Me. m_name = N
Me. m_length = L
Me. chargetype = C
End sub
Public property get thename as string
Thename = me. m_name
End Property
Public property get thelength as string
Thelength = me. m_length
End Property
Public property get chargetype as string
Chargetype = me. m_chargetype
End Property
Public property set chargetype as string
If chargetype <> "" then
Me. m_chargetype = "Freeway"
Else
Chargetype = chargetype
End if
End Property
End Class
And here's a test agent that creates object of both classes. obviusly, that code must (and does) include use statements that name the two libraries.
'Options Section
Option public
Option declare
Use "roadclasses"
Use "carclasses"
Sub initialize
Dim mycarobj as new carclass ("Honda Jazz", 120,100)
Dim myroadobj as new roadclass ("M4", 500, "tollway ")
MessageBox "objects defined! "
End sub
And here's how the objects look in the Lotus script debugger when I 've run my test agent:
So far, so easy. now I want to extend carclass to include some info about the roads on which it can travel. I do this by creating an array of roadclass objects as a member of carclass, remembering to add the line use "roadclasses" to the options section of the carclasses library, so that carclass knows about roadclass.
'In options
Use "roadclasses"
Public class carclass
Private m_name as string
Private m_topspeedkmh as integer
Private m_weight as string
Private m_permittedroads () as roadclass
sub new (n, k, W)
me. m_name = n
me. m_topspeedkmh = k
me. m_weight = W
redim me. m_permittedroads (0)
end sub
Public Function addroad (newroad as roadclass)
Dim arraysize as integer
If me. m_permittedroads (0) is nothing then
Set me. m_permittedroads (0) = newroad
Else
Arraysize = ubound (Me. m_permittedroads)
Redim preserve me. m_permittedroads (arraysize + 1)
Set me. m_permittedroads (arraysize + 1) = newroad
End if
End Function
Public property get thename as string
Thename = me. m_name
End Property
Public property get topspeedkmh as integer
Topspeedkmh = me. m_topspeedkmh
End Property
Public property get weight as string
Weight = me. m_weight
End Property
End Class
I then modify the test agent to pass some roadclass objects into my carclass object. Here's how the Code and its results look in the domino Debugger:
You can see how the m_permittedroads property of the mycarobj contains an array of roadclass objects, as we intended. but what happens if we also want to do the reverse of this; I. e. I want my roadclass object to have an array of carclass objects, which are the types of car that are permitted to drive on my road?
Here's how I might try to set that up in carclass class. you can see that I 've added a use statement to pull in the carclasses library. I 've then setup a class variable that is an array of carclass objects.
'In options
Use "carclasses"
Public class roadclass
Private m_name as string
Private m_length as string
Private m_chargetype as string
Private m_cartypes () as carclass
....
And here is where it all falls down. the Domino designer won't save this Code; it will throw the error "roadclasses (options): 3: error loading use or uselsx module: carclasses ".
Why won't it load the "carclasses "? It's because the "carclasses" library is already loading the "roadclasses" library via its use statement. and as I said earlier, two Lotus script libraries cannot "LOAD" each other. that wocould put us you an infinite loop where carclasses uses roadclasses, which uses carclasses, which uses roadclasses .... and round, and round we go. not suprising then that the designer throws a wobbler.
Solution
One possible solution is to put both classes in the same library, but this leads to an inflexibility that might end up causing more problems than it solves.
My answer is to instantiate my class objects as type variant, rather than as their actual class-types. the designer does not do compile-time type checking for variants, so we don't then need to have each library contain a use statement that tries to load up the other. only the calling code-our test agent in this case-needs to load up the two libraries. this allows us to eat our cake and still have it.
The code below shows the changes: the m_permittedroads class variable and the newroad parameter of the addroad function are both now defined as variants. this means that we no longer have to include a use "roadclasses" line in the options Section of the Library; we merely need have both libraries loaded in the calling Agent, as we did previusly. the roadclass objects are declared and instantiated in the calling test agent, and then passed into carclass's addroad method as a variant.
I 've also added a permittedroads get property so that we can access the variable later on and test what it is and what it can do. here's the modified carclass library. note that the problematic use "roadclass" line is gone as we no longer need it.
Public class carclass
Private m_name as string
Private m_topspeedkmh as integer
Private m_weight as string
Private m_permittedroads () as Variant
sub new (n, k, W)
me. m_name = n
me. m_topspeedkmh = k
me. m_weight = W
redim me. m_permittedroads (0)
end sub
Public Function addroad (newroad as variant)
Dim arraysize as integer
If me. m_permittedroads (0) is nothing then
Set me. m_permittedroads (0) = newroad
Else
Arraysize = ubound (Me. m_permittedroads
)
Redim preserve me. m_permittedroads (
Arraysize + 1)
Set me. m_permittedroads (arraysize + 1)
= Newroad
End if
End Function
Public property get thename as string
Thename = me. m_name
End Property
Public property get topspeedkmh as integer
Topspeedkmh = me. m_topspeedkmh
End Property
Public property get weight as string
Weight = me. m_weight
End Property
Public property get permittedroads as Variant
Permittedroads = me. m_permittedroads
End Property
End Class
Here's the modified calling Agent as it appears on the Lotus script debugger. I 've called the New permittedroads property of mycarobj tor return the first of the roadclass objects that I passed into it on the agent's two previous lines. although this object is returned as type variant (as displayed in the degugger), I can still access it's thename property, which proves that it's really a roadclass object.