Looking Stupid
A simple way of avoiding the implicit variable is to use the one variable you have, Result:
function Apples(nb : Integer) : String;
begin
Result := IntToStr(nb);
Result := Result + ' apple(s)';
end;
While that does look stupid, if you look behind the code at asm, it is much simpler now:;
Project65.dpr.31: begin 005D82B0 53 push ebx 005D82B1 56 push esi 005D82B2 8BDA mov ebx,edx 005D82B4 8BF0 mov esi,eax Project65.dpr.32: Result := IntToStr(nb); 005D82B6 8BD3 mov edx,ebx 005D82B8 8BC6 mov eax,esi 005D82BA E8D15FE4FF call IntToStr Project65.dpr.33: Result := Result + ' apple(s)'; 005D82BF 8BC3 mov eax,ebx 005D82C1 BADC825D00 mov edx,$005d82dc 005D82C6 E819F9E2FF call @UStrCat Project65.dpr.34: end; 005D82CB 5E pop esi 005D82CC 5B pop ebx
And it executes about twice faster as well, and as a bonus, it will be even faster in multi-threaded applications due to reduced pressure on the memory-manager.
And if you inline the functions, the second one will still keep its advantage, as inlining will only move the implicit variable and frame to the function where the inlining takes place.
Not so stupid after all
Note that this “optimization” use of an explicit local variable can be leveraged with all reference-counted types (dynamic arrays, interfaces, objects in ARC compilers…), and it can also help with debugging, as it makes it very simple to inspect the intermediate returned values.
So sometimes, it can pay twice to write a little more code: it’ll be easier to debug/maintain, and it will run faster.
That was for a single concatenation. What happens if you have many?
Check the followup article: Efficient String Building in Delphi.
Hello Eric!
Does DWScript have functions that avoid UStrAsg, LStrAsg etc. which are toxic for multithreaded applications?
Yes, whenever they appear in the top of the profiling results, and when it’s reasonable complexity-wise.
Interesting, but this seems like premature optimization and reducing the readability of code just to make a string concatenation faster. How fast is the string concatenation now? It’s hard to imagine a single concatenation becoming a bottleneck.
With D7 there is almost no difference between the two methods.
But… this is faster.
function ApplesFormatStr(nb : Integer) : String;
begin
Result := Format(‘%d apple(s)’,[nb]);
end;
@sam: IntToStr was just picked as an example of a simple function returning a string. Under D7 you should see a difference as well (did you test with FastMM or the default D7 memory manager?)
@joseph: Of course you should check with a profiler first 😉
However for readability, this is not so clear-cut, in a more real-world example with longer strings, longer functions names, etc. you’re bound to need line breaks as well, so length-wise, it’ll be similar.
Yet the longer form with explicit assignment and step-by-step concatenation will be more easily debugable and maintainable (more break point locations, ability to inspect intermediate steps easily, more detailed feedback for crash call stacks, etc.).
IMHO it’s one of those case where compact code isn’t really more readable, but is definitely less maintainable and less efficient to boot.