To Dim or not to Dim
For a reason I can’t quite put my hands on, in LotusScript variables are not declared using a unified syntax. Sometimes you have to use the Dim keyword, and sometimes you don’t. I think Dim actually means “declare a variable with local scope”, which means, local to the body of a procedure (a procedure in LS is a function, a sub or a method) or local to a module. But then again, you do not use Dim to declare member variables of classes, although they are local to that class. So just remember: No Dim in class bodies, but in modules and procedures. You do not use Dim for constants by the way, just for variables. For constants, use the Const keyword.
Sub foo messagebox bar End Sub
Merely by referencing the undefined symbol “bar”, LS will treat it as a Variant with value Nothing instead of issuing an error. This can lead to bugs which are very difficult to track down, because a typo in an identifier will still make your code run; it just won’t do what you expect. As I cannot think of any situation where one would want to access a variable without defining it first to actually carry some value, I can only flag this behavior flawed design. As user Papa pointed out in the comments section, you can fortunately force the compiler to reject references to undefined symbols by putting “Option Explicit” somewhere in your declarations section. I strongly suggest doing so when setting up a new project.
Even after programming for several weeks, I still can’t get used to the completely awkward and inconsistent rules for how you call procedures. For example, you may call subs using the Call keyword. If you do that, you can decide whether you want to omit the parentheses when the sub does not take any arguments. However, without Call, it is forbidden to use parentheses if the sub doesn’t take any arguments! Moreover, Call cannot be used for assigning a function’s return value to some variable, so you will have to use the “normal” syntax in these cases. BUT! Of course there is an exception, namely that when assigning from the sub, you now may use empty parentheses when the function takes no arguments (just don’t you dare to use Call!) So why use Call at all? I don’t know! It’s completely useless. Find below the Call insanity summarized in all its glory:
Call f2 Call f2() f2 f2() 'illegal! x = f2 x = f2() x = Call f2 'illegal! x = Call f2() 'illegal!
Nice huh? There is another catch related to how arguments are passed to procedures. LotusScript provides two semantically different ways: Passing by value and passing by reference. Get this:
Dim x as new SomeClass foo(x)
This code won’t compile, because it very likely does NOT do what you think it does. Here we declare a variable x pointing to an object of class SomeClass. Next, we pass it as an argument to procedure foo, but we pass it by value, which is illegal for objects. The catch in this example is that you have to read the parentheses around x as being part of the argument to foo, and not (as you probably expected) as part of the call syntax. Parentheses around a single argument is simply LotusScript’s way to explicitly say: “Pass this argument by value”. However, be careful: There is another catch. When using the Call keyword instead to invoke the function above, the parentheses are in fact now part of the call statement itself, which means, x will be passed by reference, which is fine. So in order to produce the same error when using Call, you would have to alter the code to look like this:
Dim x as new SomeClass Call foo((x))
NULL Is Not NOTHING
Any expression except an object reference or a Variant that contains an object reference.
Which, of course, you may not even know in advance, otherwise you wouldn’t have used a Variant, no? (Okay, except for the case where the language forces you to use them, see below!)
Working with arrays in LS is the most tedious and irritating thing I have seen so far. In LS, there are two kinds of arrays: Fixed and dynamic ones. With the exception that the latter aren’t really dynamic: Their only “dynamics” are that you can omit the dimensionality when declaring them. As soon as you work with them however, you have to Redim them for the correct dimensionality you need. No array.push(). What’s even weirder is that you cannot assign something to a variable declared as an array — only to its components. For example, it is perfectly fine to do this:
Dim arr(5) as Integer arr(0) = 1
However, you can’t do this:
Dim arr() as Integer arr = functionReturningArray() 'illegal arr() = functionReturningArray() 'illegal, works in VB Set arr = functionReturningArray() 'illegal Set arr() = functionReturningArray() 'illegal
So how you assign an array you ask? You have to declare the array as Variant, in both the function returning it and the variable receiving it:
Dim arr as Variant arr = functionReturningArrayDeclaredAsVariant()
User defined types
Functions in LS may return a reference to a class instance, but not to a user defined type. Why? I don’t know. The practical implication is that no one uses user defined types but simply abuses the class concept to create data structures. So just remember, don’t use UDTs if you plan to use them as return values from functions; use classes instead.
Lists are no lists
You also wondered about the List type? Me too, mainly because it’s not a list type. It’s actually an associative array (a “map” in Java terminology) so don’t get too confused.
The bottom line
Okay, this is it so far; my revised version of what initially started as a rant about LotusScript… I hope it helps those people who are new to LotusScript programming (and who maybe come from more popular languages like Java) to cope with some of the not-so-intuitive things about the LotusScript language.