Skip to content

LotusScript Classes Deep Dive Part Three

In part one I covered the basics of what constitutes a Class in LotusScript / VoltScript. In part two I covered abstract classes, base and derived classes. But there are more things that can be done with classes and properties.

Properties Outside of Classes

First, a little digression on Properties. Classes are not the only place where properties can be used. They can also be used as Globals in Script files. In the Domino Designer IDE, this means any Declarations area, including in Forms and Views. One good reason for using them is that you can just define the Get part.

In DOMI we used properties in the domiConstantsBE Script Library. But we also used Constants. So why both? Well, a constant is...constant. It is cached, so even if you change the constant value in the script library, dependent code still picks up the old version. Variables don't help, because they cannot have a value assigned to them in the Declarations area, they can only be declared. However, if you use a Property and call the constant, it doesn't cache the value. Obviously for variable values like the Sametime URL, it would be a support nightmare if we had a scenario where a developer would update the value but it would not be applied. Properties solved that problem.

The syntax is exactly the same as in a class. But there is an additional keyword that can be applied to properties when they are outside of a class, as well as Private and Public - static.

Static

I blogged a number of years ago about the Static keyword, a blog post a number of people have pointed me to when the topic has come up. At the time I only talked about using Static for variables within a Sub or Function, and I was only using it to lazy load something like a keyword view, with code like this:

Function getKeyView As NotesView
    Dim session As New NotesSession
    Static mkeyView As NotesView
    If (keyView Is Nothing) Then Set keyView = session.currentDatabase.getView("Keywords")
    Set getKeyView = keyView
End Function

But Static can be used for more than just variables. It can be used at Function or Sub level and it can also be used at Property level. When used at Property level, all variables within the Property are automatically static. Presumably this is also the case when using Static Function getFoo() or Static Sub doBar(), I'll leave it to someone else to verify that.

This may seem of academic interest but of little benefit. However, there are three points I've covered in this blog post that make this very useful:

  1. Variables can only be declared as globals, a value cannot be assigned.
  2. Properties can be declared as globals - which includes the code within the Getter or Setter.
  3. Applying Static to the whole Property or a variable within a Property makes it persist between calls to the Property.

When you combine this with the topic of this blog series - Classes - you get a very interesting outcome. I've only seen it mentioned in one blog post, and it's extensively used in a certain OpenNTF project. That project and the blog post about it brings me full circle to the start of this blog series, because the project is OpenDOM and the blog post is by the originator of that project, Alain H Romedenne. There may have been other blog posts and other projects that used the technique, but so much knowledge on this platform has been lost as those who drank deep from the well have moved on and their projects left to languish by the community.

As I read Alain's blog post, and after years of working with Java, the technique sounded very familiar. Alain uses Static Property to create variables that created an instance of a class and be able to refer to it in a static manner. In Java this is similar to the Singleton Pattern with enums. The technique could be particularly useful if you have classes where you only need a single instance, for example helpers or builders, and maybe configuration objects.

Imagine the following class.

Public Class Config
    Private version_ as String

    Property Get version as String
        If (me.version_ = "") Then
            Call loadVars()
        End If
        version = Me.version_
    End Property

    Private Sub loadVars()
        ' E.g. load from a document
    End Sub
End Class

Here we are using static values, but imagine this was loading values from a Notes document. We can then add a property to lazy load and always return a single instance of the class with the following code.

Public Property Get Config As Config
    Static this As Config
    If (this Is Nothing) Then
        Set this = New Config()
    End If
    Set Config = this
End Property

Developers can then just use Config.version without needing to do Dim Config as new Config.

One point of difference to Alain's blog post is that he has Static against the Property as well. Based on my testing, that isn't needed. The Delete sub is a good way to test this, and that is only called at the end of all code. As I mentioned before, if you wanted multiple variables within the Config Property, you could place Static at the Property level instead of the variable level. But adding it at the variable level is sufficient.

The second point is scope. In Java Singletons are scoped to the JVM, which is why you need to use AtomicBoolean, AtomicInteger etc instead of scalars. In LotusScript they are scoped differently.

  • If the Property is in an Agent or a Script Library that the Agent uses, the property is scoped just to the run of that agent.
  • If the Property is in a Form or a Script Library that the Form uses, the property is scoped to that Form. All events, fields and actions on that Form will share the same instance. However, if you have an agent that uses the script library and run it while you have the Form open, it will use an instance scoped to the Agent and delete it at the end of the agent call.
  • If the Property is in Database Script or a Script Library that the Database Script uses, the property is scoped to the Database Script and all events within it. The Form will use its own instance of the Property. The agent will use its own instance of the Property.

In VoltScript it is much simpler. Everything is most analogous to an Agent, so it persists for the life of the call.

I enigmatically raised the topic of singletons on OpenNTF Discord last week. As I mentioned, this seems similar to the singleton pattern. We had some discussions internally about adding a Singleton keyword to VoltScript to wrap this functionality. However, it doesn't quite work like Singletons in Java or other languages, so we have decided it would cause confusion because it could not work as developers would expect. It would be syntactic obscurantism, a term I came across in a blog post about ES6 classes. However, as a design pattern, it is very useful and we are definitely looking at useful ways to highlight this and other useful design patterns in documentation or tooling.

This may seem everything about classes. But there is one more LotusScript function that is relevant, admittedly obliquely, but very usefully.