How slow is an ampersand?
Tue 8 Feb 2005, 11:45 AMTweet
by Ben Langhinrichs
Thomas Gumz brings up a point in a post on the Notes 6 Gold forum about the inefficiency of using an ampersand ("&") to concatenate strings:
...by all means don't concatenate all your strings via "&" (because this is slow and inefficient).Now, I am a bit of an efficiency nut, but while I have heard this before, I continue to use ampersand a lot. How much slower do you think it really is? Anybody have experience with this? Should I go rewrite the places that use ampersands to use plus signs instead? Or is this too small to matter on today's modern systems, and should I just remember it going forward?
Use "+" instead.
BAD :strBody = strBody & "Fax " & conFaxNumber
GOOD: strBody = strBody + "Fax " + conFaxNumber
If conFaxNumber isn't a string, then use this:
strBody = strBody + "Fax " + Cstr(conFaxNumber)
Thomas - IBM
Copyright © 2005 Genii Software Ltd.
What has been said:
286.1. Christopher Byrne (02/08/2005 09:02 AM)
My understanding is that the ampersand (&) was most useful to concatenate strings from different value types.
So to me, the answer is "Depends on the situation". If I know I am only doing a concatenation of string elements, sure it might be more inefficient if the & forces an evaluation everytime.
If not, what is less efficient?
strValue + ": " + Cstr(iMeters)
strValue + ": " & iMeters
286.2. Damien Katz (02/08/2005 09:18 AM)
While I can't be sure, I think Thomas is wrong here. I'll bet you'll see no noticable difference if you test the execution times.
286.3. Jess Stratton (02/08/2005 10:58 AM)
I may be being REALLY naive on this one, so please don't make fun, but I would think it would be the opposite. According to the Lotus Help on concatenation operators:
Use the ampersand (&) operator to ensure a concatenation operation. The plus (+) operator also concatenates two character strings, but LotusScript determines whether to interpret the plus as a concatenation operator or an addition operator on the basis of the operands in the expression in which it appears.
Wouldn't it take longer using a "+" because LotusScript has to first analyze that it's not supposed to be adding it, but rather concatenating it?
286.4. Colin Pretorius (02/08/2005 11:00 AM)
I recall a circa R5 performance/best practices document saying that & was recommended because it didn't require explicit type checks, while + did. I used to religiously + everything, read that article, then switched to &.
The best is to test, and I just did :) Not very scientific, but plussing two strings was no faster than ampersanding two strings, (12 seconds over 2 million iterations) but as soon as I threw an integer into the mix (str1 + str2 + cstr(10) versus str1 & str2 & 10), the ampersanding was faster, 15 seconds to 17.
I re-ran it a few times with consistent results, but this is on my dodgy (and busy) old Linux box using Wine, so ymmv.
286.5. Ben Langhinrichs (02/08/2005 11:05 AM)
While not definitive, that certainly seems like enough feedback that I won't change my habits (until I hear something different, at least). Thanks all!
286.6. Jess Stratton (02/08/2005 01:15 PM)
How do you do a test like that? One that counts it? I've always wondered how a performance test like that is done...
286.7. Julian Robichaux (02/08/2005 03:14 PM)
I think it just depends on what your interpretation of "slow" is. Or really, what you consider "fast enough".
Without doing any tests, let's say that & is indeed slower than +, because it has to explicitly cast everything to a string before it concatenates. And let's say that because of that, it takes 0.00002 seconds to concatenate with & instead of 0.00001 seconds with + (wild ass guess, but concatenation is virtually instantaneous if you try to clock it, and even if I'm off by a factor of 10 it'll still make my point). So if you're doing something crazy in your script and you concatenate 100 times with &, you've just wasted 0.001 seconds of your user's time.
Now let's say that you decide to use + instead, and your concatenation is:
newString = oldString + doc.SomeField(0)
Everything compiles, but at some point a number gets in the doc.SomeField field, and causes a runtime error, which causes the agent not to run properly and makes you have to troubleshoot.
Which is slower: losing 0.001 seconds per agent run, or noticing, tracking down, and fixing a runtime error?
I'll take the less efficient & concatenation in that case.
And sure, you could code it as:
newString = oldString + CStr(doc.SomeField(0))
but how long did it take you to type that extra CStr() for every concatenation? 3 seconds each time? It'll take a lot of agent runs to make up that kind of lost time.
Yeah, the ampersand works for me, slower or not.
286.8. Colin Pretorius (02/08/2005 03:27 PM)
Jess, there are a couple of ways. The quick-and-dirtiest is to call the timer() function in LotusScript - that gives you the seconds since midnight, and you can just take readings before and after and compare them. The midnight thing means you need a bit more logic if you're planning to leave something running overnight :)
Another longwinded way is to instantiate two NotesDateTime objects (a start and a finish), call setNow() on the first before you start a section and call setNow() on the other when you're done, and then call finish.timeDifference(start) to get the difference in seconds.
286.9. Nathan T. Freeman (02/09/2005 03:08 AM)
startTime = Now
(Now - startTime)*86400
286.10. Colin Pretorius (02/09/2005 04:48 AM)
I prefer using timer() in favour of calculating the difference between double-valued date variants and having to stop and remember/calculate the 86400 bit to convert to seconds.
I guess I should have mentioned it as well though. Sorry Nathan, was there anything else I left out?
286.11. Jess Stratton (02/09/2005 10:31 AM)
Thanks everyone! I don't know why I assumed it would be more complicated than that...
286.12. Thomas Gumz (02/09/2005 12:20 PM)
Both Colin's and Nathan's methods work, but the results are in seconds, which, for lots of benchmarks, simply isn't good enough.
Fortunately, Notes/Domino lets you use a high resolution timer (not measured in sconds, but CPU 'ticks').
Here's some sample code on how to use them:
Dim lStart as Long
DIm lStop Long
lStart = Getthreadinfo(LSI_THREAD_TICKS)
'do some work...
lStop = Getthreadinfo(LSI_THREAD_TICKS)
msgbox "Ticks: " & lStop - lStart
286.13. Colin Pretorius (02/09/2005 12:58 PM)
Now _that_ rocks. Thanks!
286.14. Colin Pretorius (02/09/2005 01:19 PM)
...and I see GetThreadInfo in the help db. Naughty me ;)
286.15. Alain H Romedenne (02/18/2005 05:58 AM)
While timing script routines, note lsi_info(98), lsi_info(99) provide getThreadInfo(n) equivalence with older releases.
You'll get a precision scaling down to microseconds on Wintel platforms while using Stopwatches class from org.OpenNTF.OpenDOM project.
286.16. harkpabst_meliantrop (26.01.2006 08:39)
Thomas, I not only like the hi-res timer code, but also the fact that it uses an ampersand instead of + Cstr(long) .... ;-)