Interfaces & Abstract Classes with LotusScript
Interface and abstract classes define objects properties and methods, just as ordinary classes do. One generally creates as many objects as necessary from standard classes, while interface classes are solely intended to describe contracts that future objects will guarantee. Interfaces classes usually contain no code and can't be used to instantiate objects. In turn abstract classes prototype properties and methods. Abstract classes can't be instantiated either and require to be derived so that its subclasses benefit from their code. Compilers closely control interface compliant classes and usually prevent from interface or abstract classes instantiations.Designers usually resort to interface or abstract classes to build loosely coupled application code that's more adaptable, more maintainable and ends up being more robust. Although such class constructs are missing from native LotusScript, those object oriented design concepts can be implemented in your LotusScript code with little effort.
As an exemple, consider designing a LotusScript.io.File class that holds the following subset of attributes and operations: canWrite( ), getAbsolutePath( ), length( ), list( ), renameTo( ). You may either develop a full LotusScript solution, either build an LS2J based solution, either resort to Windows Script Host COM object library or even call Windows/32 native functions. Defining iFile interface class sounds a valuable approach that exhibits properties and methods regardless of the implemented inner workings. While your calling code relies on a stable interface, your concrete implementations can vary at will or be changed without notice. Doing so you're building a loosely coupled Notes or Domino application.
Figure 1: StopWatches UML Class Diagram
OpenDOM open source project you can download from www.openntf.org contains numerous code samples benefitting from interfaces and abstract classes design constructs. Its LotusScript.lang.StopWatches library uses iTicker public interface in four different implementations accommodating LotusScript release 3 and 4+, Windows/16 and Windows/32 contexts. LotusScript.lang.Rn or LotusScript.windows.winnn packages, or namespaces, contain iTicker interface compliant concrete classes. StopWatches public class internal iTicker engine gets loaded dynamically according to the most appropriate situation.
You can prevent from objects instantiation, and make sure properties and methods get derived or overridden. But creating private LotusScript class constructors as in ..
<noteName>: <eventName>: <lineNumber>: Illegal PRIVATE declaration of: NEW
As LotusScript does not natively support interface classes or private constructors as above I adopted another approach. I prevent from interface or abstracts classes instantiation at runtime only throwing exception in class constructors, I force properties and methods to be derived throwing equivalent runtime exceptions as in :
Once I established my interface, I can devise to write as many concrete classes implementing it and provide a factory class or routine serving context dependent objects :
OpenDOM LotusScript.lang.Factory class creates objects this way. It is inspired from « Performance Considerations for Domino Applications » IBM redbook whose « B-2 Dynamic Script Library Loading » worth reading appendix explains how to dynamically load LotusScript libraries in your object oriented programs. While IBM code performs objects dynamic instantiation, attentive reading reveals such is accomplished using variants that defeat compiler time type checks. Adding interface classes your code overcomes this obstacle and offers multiple advantages :
Places of interest:
OpenDOM open source project you can download from www.openntf.org contains numerous code samples benefitting from interfaces and abstract classes design constructs. Its LotusScript.lang.StopWatches library uses iTicker public interface in four different implementations accommodating LotusScript release 3 and 4+, Windows/16 and Windows/32 contexts. LotusScript.lang.Rn or LotusScript.windows.winnn packages, or namespaces, contain iTicker interface compliant concrete classes. StopWatches public class internal iTicker engine gets loaded dynamically according to the most appropriate situation.
You can prevent from objects instantiation, and make sure properties and methods get derived or overridden. But creating private LotusScript class constructors as in ..
.. throws the following compiler exception :Public Class iVehicle
Private Sub New
End Sub
End Class ' iVehicle
<noteName>: <eventName>: <lineNumber>: Illegal PRIVATE declaration of: NEW
As LotusScript does not natively support interface classes or private constructors as above I adopted another approach. I prevent from interface or abstracts classes instantiation at runtime only throwing exception in class constructors, I force properties and methods to be derived throwing equivalent runtime exceptions as in :
%INCLUDE "LsErr.lss"
Public Class iVehicle '
Public Sub New ' This forbids interface instantiation, please derive me !
If Typename( Me ) = "IVEHICLE" Then Error ErrNotAnObject
End Sub ' New
Public Property Get Color As NotesColor
Error errPropGetNotDefined
End Property ' Color
Public Property Set Price As Currency
Error errPropSetNotDefined
End Property ' Price
Public Sub starts( )
Error ErrNotAMethod
End Sub ' starts( )
End Class ' iVehicle
Public Class aShuttle
Public Property Get isFree As Boolean '
Error errPropSetNotDefined
End Property ' isFree
End Class ' aShuttle
Once I established my interface, I can devise to write as many concrete classes implementing it and provide a factory class or routine serving context dependent objects :
Private Class Car As iVehicle
' Your code goes here ..
End Class ' Car As iVehicle
Private Class Truck As iVehicle
' Your code goes here ..
End Class ' Truck As iVehicle
Public Function createVehicle As iVehicle
If ( so And so ) Then
Set Me.createVehicle = New Car
Else
Set Me.createVehicle = New Truck
End If
End Function
OpenDOM LotusScript.lang.Factory class creates objects this way. It is inspired from « Performance Considerations for Domino Applications » IBM redbook whose « B-2 Dynamic Script Library Loading » worth reading appendix explains how to dynamically load LotusScript libraries in your object oriented programs. While IBM code performs objects dynamic instantiation, attentive reading reveals such is accomplished using variants that defeat compiler time type checks. Adding interface classes your code overcomes this obstacle and offers multiple advantages :
- You're designing loosely coupled LotusScript while building application classes regardless of their internal technical alternatives you will freely accommodate,
- Early bound objects allow type safety controls to occur at compile time which is considered a best practice,
- LotusScript interpreter memory footprint increases progressively as library objects are gradually loaded. Although libraries are compiled prior to be loaded, this gets mostly unnoticed and is largely compensated by memory minimised consumption.
Places of interest:
- « Lotus Notes and Object-Oriented System Design », Mikko Valjakka
- Appendix « B-2 Dynamic Script Library Loading » in Performance Considerations for Domino Applications IBM RedBook
«Dynamic loading of LotusScript libraries» in HADSL blog - « Leveraging the Power of Object Oriented Programming in LotusScript », Jens-B Augustiny & Wild Bill Buchan
« Object Orientated Programming in LotusScript », Wild Bill Buchan - « Objektorientierung in LotusScript effizient einsetzen », Bernd Hort
Labels: abstract class, interface class, LotusScript, Object Oriented Design, Object Oriented Programming, OOD, OOP, SnTT

3 Comments:
I strongly agree with you: Interfaces and abstract classes are missing from LotusScript. We use the Error-statement in abstract methods, too, but the idea using
If Typename( Me ) = "IVEHICLE" Then...
in interfaces is simply ingenious :-)
But there is another LotusScript restriction hinders real-world usage of interfaces: You can only inherit from one superclass. Therefore the following code does not compile:
Class AObject
Public a As Integer
End Class
Class BInterface
Public Function GetB() As String
End Class
Class CObject As AObject, BInterface
' ...
End Class
But without the ability to inherit from a superclass and one to many interfaces, their usage is restricted to some simple use cases.
I really like Notes, but knowing Java, there are so many limitations... :-(
Thomas
By
Thomas Bahn, at 1:02 PM
I am curious as to how this and other fully fledged OO methods implemented in your LS code have enabled you to scale the complexity of your applications. Or have the improvements translated into more maintainable and reliable code.
As for the benefits of your method over the dynamic linking courtesy of Variants it only holds for the case of polymorphic methods. Were you to add new methods in the subclasses (your concrete implementations) they would not be accessible via the interface.
There are many more places where the LS implementations of the missing OO features are not quite there and so I wonder what is the overall benefit.
Like Thomas I have to say that once you have programmed in a more expressive language like Java (never mind smalltalk, Ruby, etc) you feel very constrained (and frustrated) by the limitations of LS.
Slawek
By
Slawek, at 1:36 AM
Thomas, Slawek,
I agree with both of you as far as LotusScript limits can be a source of frustration compared to other languages' expressivity. Although weakly typing benefits vs strongly typing remains debated on the Internet (Ruby on Rails, JavaScript vs Java .Net and the like)
However, overcoming LotusScript constraints is day-to-day Domino designers' challenge, accompanied with satisfaction and sometimes frustrations. Be as they may, that is applied to simple use cases or polymorphic situations, and combined with dynamic library loading, coding interfaces in LotusScript is worth exploring.
Cordially
Alain
By
Alain H Romedenne, at 5:47 AM
Post a Comment
Links to this post:
Create a Link
<< Home