So Here's Why I Hate LotusScript
Sat Oct 29 13:44:43 EDT 2011
For the most part, writing agents in LotusScript is the best way to go (at least when it can't be done in formula language), mostly for smoothness of interaction with the built-in libraries (no .recycle()
) and because it's less prone to running into memory problems when other agents go wonky than Java agents are. That doesn't mean I have to like it, though.
If there's one thing that drives me nuts about LotusScript more than any other aspect, it's its handling of arrays. This came to the fore with one of my recent projects, which involves spitting out the contents of a view, which in turn entails lots of use of entry.ColumnValues
. My first, quick-and-dirty draft ran into an early performance issue, which is that every call of .ColumnValues
on a NotesViewEntry seems to be as expensive as the first, meaning that the class doesn't do any internal cacheing and has to re-fetch it every time. Ugh, fine - I'll just assign the value to a new variable at the start:
Dim colValues as Variant
colValues = entry.ColumnValues
Not too bad - two extra lines at the start of a loop is a small price to pay for a significant speed improvement. Unfortunately, it doesn't work - it throws a Type Mismatch error at runtime. After doing a TypeName()
on entry.ColumnValues
, I saw that it considers it "VARIANT( )", an array of Variants, which makes sense. It's a bit weird, since I've stored arrays in Variants before, but whatever - with a quick code adjustment, we're off to the races:
Dim colValues() as Variant
colValues = entry.ColumnValues
Great! Now hit Ctrl-S and... compiler error. You're not allowed to assign to the entirety of an array like that. Argh! So I guess I'm going to have to make my new array manually and loop through the original to copy each entry over individually. If you're familiar with another scripting language, that probably sounds like a simple task, but LotusScript's array annoyances continue. Because this is like BASIC, you can't just do "colValues.add(something)
" - you have to ReDim
the array to the right size. Here's the code I ended up with:
Dim columnValues() As Variant
ReDim columnValues(-1 To -1)
ForAll columnValue In entry.ColumnValues
If UBound(columnValues) = -1 Then
ReDim columnValues(0 To 0)
Else
ReDim Preserve columnValues(0 To UBound(columnValues)+1)
End If
columnValues(UBound(columnValues)) = columnValue
End ForAll
Before you look at that "-1 to -1" crap and deem me insane, hear me out. Though the NotesViewEntry doesn't cache its property value, the ForAll
loop does, meaning that, according to the profiler, ColumnValues
is only called once for each view entry, which is about as efficient as it gets. All that extra crap about ReDim
'ing the array over and over instead of just once is essentially "free" compared to the expense of the product object call, so it ends up being completely worth it.