Look at the following code and guess the error message.
Class Person Public firstName as String End Class Sub Initialize Dim p as New Person Call outerPrint(p) End Sub Sub outerPrint(msg as Variant) innerPrint(msg) End Sub Sub innerPrint(msg as Variant) If (TypeName(msg) = "PERSON") Then Print msg.firstName Else Print msg End If End Sub
The error message received will be a Type Mismatch, on the line
innerPrint(msg). But the cause might be harder to work out - although the title of this blog post might point you in the direction.
Firstly, there’s no coding error in the
innerPrint sub. If you add error handling to
innerPrint(), it won’t log anything. Indeed if you try printing something on the first line of the
innerPrint() sub, it won’t print anything. When the Type Mismatch error logs on the line
innerPrint(msg), that is specifically the line and the Type Mismatch is on passing
msg into that method.
There are two uses for parentheses when calling a LotusScript method. And that is also why it won’t be possible to remove the
Call keyword for VoltScript. Parentheses are used to just pass arguments only if you include the keyword
Call. But (accidentally) the
Call keyword has been omitted in
innerPrint(msg). So the second usage for parentheses when calling methods is being used, namely that the parentheses mean “pass the variable by value rather than by reference”. If it had been written
innerPrint (msg), itmight have been more obvious. You could also use
Call innerPrint((msg)), in which case the outer parentheses denote arguments to pass and the inner parentheses identify this argument as being passed by value.
Of course pass by value can be explicitly required on a method by using the
ByVal keyword. So
Sub innerPrint(ByVal msg as Variant) means the argument being passed into
innerPrint will always be passed by value rather than by reference. The calling code cannot override this. But wrapping an argument in parentheses when calling the method will also pass it by value. This isn’t exclusive to LotusScript. It’s also the same in Visual Basic.
But only scalars can be passed by value in LotusScript. You cannot pass an array, a List, a Type instance or an object by value. If the code had been
Call outerPrint("Hello World"), it would have run fine. But because we’re passing an object - an instance of the Person class - it throws an error at runtime. If we had called
innerPrint directly from the
Sub Initialize, the compiler would have generated an error. But because the Person object is being passed into the
outerPrint method as a Variant and not being re-cast explicitly as an instance of the Person class, the compiler cannot generate an error.
Typically this would only bite a developer if they’re writing a framework, something where arguments are defined as Variants because the code needs to handle various different datatypes. But it’s one that, when it bites, it can be harder to identify. This is because passing by value vs by reference is done so rarely in LotusScript.