Genii Weblog

How slow is an ampersand?

Tue 8 Feb 2005, 11:45 AM



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).

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
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?

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)

or

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)

Colin,

How do you do a test like that? One that counts it? I've always wondered how a performance test like that is done...

Thanks!

Jess :-)


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.

- Julian


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)

LOL.

startTime = Now

[process]

(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:

%include "lsprcval.lss"

Dim lStart as Long

DIm lStop Long

lStart = Getthreadinfo(LSI_THREAD_TICKS)

'do some work...

lStop = Getthreadinfo(LSI_THREAD_TICKS)

msgbox "Ticks: " & lStop - lStart

[a [href]http://thomasgumz.net/[/href]Thomas[/a]


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) .... ;-)