Jump to content
Marsil

Declaring inline variable inside a loop vs. before the loop

Recommended Posts

Hello,

 

Any differences between declaring an inline variable inside a loop and declaring it before the loop?

I know that declaring an inline variable inside a loop limits its scope which is a good thing, but any 

difference in term of performance, memory allocation, extra work,...especially in big loops, or anything

I don't know about?

 

Many thanks!

 

 

Outside loop

var FileRec : TSearchRec;
while not StopSearch do
  begin
    ...
    GetData (FileRec);
    UseData;
    ...
  end;

 

Inside loop

while not StopSearch do
  begin
    ...
    var FileRec : TSearchRec;
    GetData (FileRec);
    UseData;
    ...
  end;

 

 

 

Edited by Marsil

Share this post


Link to post

Thanks for the quick reply!

I used to declare inline variables of simple types inside the loop, but this time it's a record of type TSearchRec,

and I wondered if that was going to degrade performance. I guess that goes for other structured types  too.

 

Share this post


Link to post

It doesn't matter what type of variable. The reason for this is the unnecessary repeated creation of the variable. We know that we only need to create it once.

  • Thanks 1

Share this post


Link to post

Thanks again, so a rule of thumb is never to declare inline variables inside a loop

 

Share this post


Link to post

I always declare it inside the loop if it is not used outside. Declaring it outside may lead to hard to find bugs.

  • Like 1
  • Thanks 1

Share this post


Link to post
Just now, EugeneK said:

I always declare it inside the loop if it is not used outside. Declaring it outside may lead to hard to find bugs.

That was one of my thoughts too!, Limiting scope is good, but we cannot get all good things at once can we?

Share this post


Link to post

You may either measure the time for both way of doing it, of look at the assembly code generated.

  • Like 4

Share this post


Link to post
1 hour ago, FPiette said:

You may either measure the time for both way of doing it, of look at the assembly code generated.

Yes I'm planning to do that but I thought I may get more useful insights by asking first.

What I know now is that an inline variable is allocated at the point of declaration, not at the start of the block where

it is declared.  If I am not mistaken.

 

 

Share this post


Link to post

 

Just ran a quick test (I'm not sure if it is a very good test) :

 

  
 // Before loop
 
  var FileRec : TSearchRec;
  var Stopwatch := TStopwatch.StartNew;
  for var i := 1 to 100000000 do
    begin
      FileRec.Name := 'Test';
    end;
  Log (Stopwatch.ElapsedMilliseconds);  // logs 205 
  
  
  // Inside loop
  var Stopwatch := TStopwatch.StartNew;
  for var i := 1 to 100000000 do
    begin
      var FileRec : TSearchRec;
      FileRec.Name := 'Test';
    end;
  Log (Stopwatch.ElapsedMilliseconds);   // logs 3129   (more than 15x)
  
  

 

 

But when changing the inline variable type to Integer

 

declare before loop timings:

161
161
161
161
161
 

declare  Inside loop timings:

161
160
160
161
160

 

Increasing loop to 100 million times:

before 1624
inside 1617

 

for a loop of millions times this is really negligible difference, nothing at all.

So declaring simple types inside a loop may be the better choice after all??

 

Edited by Marsil
  • Like 2

Share this post


Link to post

Running a more realistic loop count of 100,000 times:

 

TSearchRec var declared

before loop :  0 ms

inside loop:  3 ms

 

3 ms difference each 100,000 loop is a very small price to pay in exchange of encapsulation earned by limiting scope?? what do you think?

 

Edited by Marsil

Share this post


Link to post
6 hours ago, Stano said:

Always before the loop.

Beware of unqualified statements involving always and never. Unless the advice is to never put pineapple on pizza. That one is just a fundamental law of nature.

 

 

6 hours ago, Marsil said:

Any differences between declaring an inline variable inside a loop and declaring it before the loop?

As you've discovered it depends on the type of the variable.

Local variables are declared on the stack and such doesn't involve the heap (i.e. the memory manager). Allocating a variable on the stack is basically free of cost.

 

However, managed types need initialization and that initialization can be costly. TSearchRec contains a string and is therefore a managed type (i.e. slow). Integer is not a managed type (i.e. fast). Additionally, managed types are wrapped in an implicit try..finally block to ensure that they're also finalized. The help probably has more info on this.

 

If you want to limit the scope just put a begin...end around the whole thing:

begin
  var FileRec : TSearchRec;
  while not StopSearch do
  begin
    ...
    GetData (FileRec);
    UseData;
    ...
  end;
end;

Apart from that, in this particular case, you are touching the file system so the performance of inside vs outside will be dwarfed by that.

 

4 hours ago, Marsil said:

Yes I'm planning to do that but I thought I may get more useful insights by asking first.

...and so the lesson here is: You don't get more useful insight by asking first.

  • Like 5

Share this post


Link to post
1 hour ago, Anders Melander said:

 

If you want to limit the scope just put a begin...end around the whole thing

I put a like for this hint!

 

2 hours ago, Anders Melander said:

...and so the lesson here is: You don't get more useful insight by asking first.

On the contrary I did get some useful information from this question and probably more coming

Share this post


Link to post
9 hours ago, Anders Melander said:
16 hours ago, Stano said:

Always before the loop.

Beware of unqualified statements involving always and never. Unless the advice is to never put pineapple on pizza. That one is just a fundamental law of nature.

I agree. I'll keep an eye on it.
I really am a layman. I was basing it on the PAL help. I have no other knowledge of it.

Share this post


Link to post
On 11/29/2023 at 4:55 PM, Marsil said:

 


while not StopSearch do
  begin
    ...
    var FileRec : TSearchRec;
    GetData (FileRec);
    UseData;
    ...
  end;

 

tSearchrec is a record that contains a managed type (the file name is a string). 

 

When managed types go out of scope, the code generated by the compiler checks if they are no longer in use and that any heap memory they occupy is freed properly. That costs time.  

On 11/29/2023 at 4:55 PM, Marsil said:

 

 

 

Share this post


Link to post

Nobody seems yet to have wondered whether the potential for behaviour change is important.

 

This is an ill posed question with no possible answer because we don't know any detail. 

 

So much heat, so little light.

 

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×