Lazarus

Programming => General => Topic started by: JernejL on March 12, 2018, 05:37:23 pm

Title: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: JernejL on March 12, 2018, 05:37:23 pm
I believe i read somewhere that the 2nd variant (early continue instead of begin..end ) is not supported for optimization in lazarus / freepascal.
 
If possible.. can someone explain what is better from compiler optimization perspective? the 2nd option is surely more readable, but i'm more interested in raw performance - what will perform better, what will optimize better in compiler - and if there's difference between lazarus and delphi regarding how this works.

Code: Pascal  [Select][+][-]
  1. for i := 0 to Actors.MaxObject-1 do begin
  2.  
  3.         if Actors.State[i] = stat_used then
  4.         with Tactor(Actors.Data[i]) do
  5.         begin
  6.  
  7.                 if (AIclass = AI_NOBRAIN) then begin // near players only.
  8.  
  9.                 end;
  10.         end;
  11. end;
  12.  

or..

Code: Pascal  [Select][+][-]
  1. for i := 0 to Actors.MaxObject-1 do begin
  2.  
  3.         if Actors.State[i] <> stat_used then continue;
  4.  
  5.         with Tactor(Actors.Data[i]) do
  6.         begin
  7.  
  8.                 if (AIclass <> AI_NOBRAIN) then continue;
  9.  
  10.         end;
  11.        
  12. end;
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Thaddy on March 12, 2018, 06:50:22 pm
It is supported but why do you do not write else instead of continue in the first continue statement: that is a single instruction on most CPU's? It is simply silly code.
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: JernejL on March 12, 2018, 07:52:07 pm
It is supported but why do you do not write else instead of continue in the first continue statement: that is a single instruction on most CPU's? It is simply silly code.

 
I'm genuinely confused on where would i use else instead of continue.. that makes no sense, can you write this on my example?
 
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: RAW on March 12, 2018, 09:27:56 pm
I would definitely prefer the first version...much more common...
ELSE ? I don't see why there must be an ELSE...  :)
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Martin_fr on March 12, 2018, 09:33:11 pm
This kind of optimization questions do not usually have a general answer.

The issue with question like "which code is better optimized by fpc?" is that "fpc" is an exact specification.

It may be that fpc 2.x does better optimization on one code, but fpc 3.0.x on the other, and no one knows what fpc 3.2 will do.

It may also be that one code performs better on intel, and the other on arm... Or 64 vs 32 bit ...

So all you can do is answer the question for one specific version of fpc, at one platform, for a given set of compiler settings.

If you want to know which version works better on your PC, just compile it, and compare.
If you know how your processor handles asm (including prediction and what not), then compile with -al, and compare the result.

------------------------------
About your problem:

If you have speed problems in a loop like yours, your problem is not to make the loop a few ticks faster.

You need a different approach.

I assume the list is potentially large, and many entries are NOT of state "stat_used"? Because if there are only a few actors, or if 99% of them are stat_used, then there is not much to gain.

You could maintain a 2nd list, with only actors of state "stat_used". Every time the state of an actor changes, it adds or removes itself.
Of course a normal list is not suited. Adding may be fast, but removal requires a search and be slow...
Use a double linked list, insertion, removal and iteration are fast.


Iteration may even be faster, than your for loop. Following a linked list, means just to read one pointer (and a check if it is nil, to end the loop)

Looping over a classic list, requires an index variable, increasing it, depending on optimization multiply it with the pointer size (that is part of one asm instruction to read the pointer), and reading the pointer.

Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Mr.Madguy on March 13, 2018, 08:22:32 am
Answer is simple: View->Debug windows->Assembler
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: User137 on March 13, 2018, 12:47:03 pm
Is this optimal if assuming the data is referred to in multiple occasions in code?
Code: Pascal  [Select][+][-]
  1. with TActor(Actors.Data[i]) do

Or was pointer reference faster?
Code: Pascal  [Select][+][-]
  1. pActor:=PActor(@Actors.Data[i]);
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: RayoGlauco on March 13, 2018, 02:15:52 pm
I suggest implementing, executing and timing every possible option.

Code: Pascal  [Select][+][-]
  1. starttick := GetTickCount;
  2. { ... loop ... }
  3. endtick := GetTickCount:
  4. elapsed := endtick - starttick;
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Nitorami on March 13, 2018, 02:56:48 pm
My personal opinion - stop wasting effort on such considerations. As Martin_fr said, first try to reduce the frequency of calls by an intelligent lookup algorithm, rather by saving one or two CPU instructions in a loop that is called 100 million times per second.
As to the code, I personally have never used a continue statement, and don't think it will ever be required, it is mostly a patch to get yourself out of poorly constructed loops. Use the language as it is meant to be, i.e. begin - end - else, and in general this will also give you the best performance. The same is true for array indexing, there is absolutely no need to confuse yourself by recurring to C style pointer arithmetics, with the only execption of multi dimensional arrays where the compiler is not (yet) smart enough to calculate addresses only once.
And don't do premature timing tests. Simplistic micro-loop benchmarks will not at all deliver results representative for the application, modern processors just don't work this linear way.
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: JernejL on March 13, 2018, 03:58:44 pm
Is this optimal if assuming the data is referred to in multiple occasions in code?
Code: Pascal  [Select][+][-]
  1. with TActor(Actors.Data[i]) do

Or was pointer reference faster?
Code: Pascal  [Select][+][-]
  1. pActor:=PActor(@Actors.Data[i]);

 
This is a good question, i wonder too which approach is better.
 
The reason i have to use continue statements is, to provide readability of code, some of conditions get a lot of depth and that after a while makes it hard to follow / maintain, it's a huge fsm machine with a lot of conditions, some of it is impractical to refactor.
 
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Nitorami on March 13, 2018, 06:09:49 pm
I suggest to use the simple "with" solution, it is easier to read and is native pascal style. Why would the developers be so stupid as to make native array indexing slower than a protracted pointer construction ? It is an old claim that pointer indexing is faster, and this may have been true long ago, but in my own benchmarks I always found the native approach a bit faster... but we are talking almost unmeasurable quantitities, +/-5% maybe. As said above, with the only exception of multidimensional arrays.
A to the "continue"... I have a certain understanding why ony would use a "break" command to quit a loop, but I am not convinced why anybody would need "continue". I don't find the complexity argument convincing, but it's your choice after all.
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Martin_fr on March 13, 2018, 06:56:28 pm
Why would the developers be so stupid as to make native array indexing slower than a protracted pointer construction ? It is an old claim that pointer indexing is faster, and this may have been true long ago, but in my own benchmarks I always found the native approach a bit faster... but we are talking almost unmeasurable quantitities, +/-5% maybe. As said above, with the only exception of multidimensional arrays.

First of all "using pointer" can refer to many different things. In my previous post, I referred to a pointer in a linked list. That is different from replacing the loop index by a pointer.

Replacing the loop index by a pointer (to the list) may or may not gain speed, and if it does it may gain just very little, and it may in future fpc versions even loose speed.
But speed differences between list-index and list-pointer have nothing to do with "the developers making it so" or "being stupid". It would simple mean that they hadn't have time to implement certain optimizations.

Unoptimized access to the loop looks approx like this:
// i starts at 0
- i := i +1
- element from loop := memory at "list_start_address + sizeof(element) * i"
  // Note that some cpu may optimize this multiplication, and it may not cost (measurable) time at all

Optimized access may look like this (depends on the cpu):
// p start at list_start_address
- p := p + sizeof(element)
- element from loop := memory at "p"

You can see the optimize version has less math to do in the loop.

I do not know how far fpc currently takes that optimization.
I also do not know how well modern CPU (with prediction, and all their tricks) compensate for the math.

--------------------------------------------------------------
A completely different approach is a linked list.

A linked list can be maintained that already is filtered. This saves time of filtering.

The code
Code: Pascal  [Select][+][-]
  1. if Actors.State[i] = stat_used then
Means that each object in the list (since the class data is not stored in the list own memory, but accessed by pointer) needs to be fetched from memory.
If there are many objects, they are likely not in the CPU cache. And fetching them becomes an expensive operation.

As I said: the link list is already filtered. No need to fetch any objects, just to find out that they can be skipped. If the percentage of stat_used objects is small, then this saves a lot of time.

And as a side effect, the linked list pointer is part of the object. So there is no separate memory for a list that needs to be in the CPU cache.
In fact, if the object itself is cleverly designed, each cache line read burst of the cpu can fetch more of the data that the loop needs, and you gain speed here too.

And one more, using a linked list, there is on index (nor a pointer to the list). Only the current object.
This saves one variable. Therefore it saves one cpu register, that can be used for something else.



Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Nitorami on March 13, 2018, 07:27:52 pm
Quote
First of all "using pointer" can refer to many different things.

Agreed, but I did not refer to your linked list example which is an entirely different issue and meant to reduce the number of accesses in the first place. You already explained that but the OP did not pick it up.

And I insist I would find pascal rather stupid if it forced me to use extra pointers instead of indexed access for best performance. Luckily, this is not the case for onedimensional loops.
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: RAW on March 13, 2018, 07:54:18 pm
What about "Binary Trees", "HashTables" or "Linked List of Dynamic Arrays" or "Databases"... I guess I read this on stackoverflow or somewhere else...
Or some ready to use FreePascal Lists: TFPList or TFPHashList ...
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Paul_ on March 13, 2018, 08:33:05 pm
What about "Binary Trees", "HashTables" or "Linked List of Dynamic Arrays" or "Databases"... I guess I read this on stackoverflow or somewhere else...
Or some ready to use FreePascal Lists: TFPList or TFPHashList ...

Good point, it's not only about loop/iteration over the list but also about data structure, what is TActor and what is the list Actors.Data ? How big is their memory footprint? Are you adding and removing list content often?

I had similar questions here: https://forum.lazarus.freepascal.org/index.php/topic,39495.90.html (https://forum.lazarus.freepascal.org/index.php/topic,39495.90.html)


Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: JernejL on March 14, 2018, 08:42:52 am
One is array of pointers and other an array of booleans to see which contain objects.
 
I think this is clearly a bad design (had good intentions), the list grows and shrinks a lot, and i will change this to a linked list.
 
Still the original question.. There is no clear info on how any pascal compilers will handle such continues in loops?
 
i'm still wondering if "with TActor(Actors.Data) do" / or "pActor:=PActor(@Actors.Data);" method is faster..
 
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: SymbolicFrank on March 14, 2018, 09:16:12 am
I agree with Nitorami: just write it in the way that makes it the most readable to you. And if turns out to be too slow, come up with a totally different (smarter) approach.

For example, I like to break up actions into separate steps as much as possible. I don't like deep nesting:

Code: Pascal  [Select][+][-]
  1. function Test(Amount, Match: Integer): Boolean;
  2. var
  3.   x: Integer;
  4. begin
  5.   Result := False;  // Initial value
  6.  
  7.   if (Amount < 0) or (Amount > SomeValue) then Exit;  // Test parameters
  8.  
  9.   for x := 0 to Amount - 1 do
  10.   begin
  11.     if (Amount mod x = 0) then Continue;  // Not this one
  12.  
  13.     if (SomeArray[x] = Match) then // Found one, do something
  14.     begin
  15.       Result := True;
  16.       Break;  // We're done
  17.     end;
  18.  
  19.     // if something else ....
  20.   end;
  21.  
  22.   // Do cleanup
  23. end;

But I would probably use an Exit instead of the Break, and a try .. finally for cleanup.
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Handoko on March 14, 2018, 09:22:08 am
Still the original question.. There is no clear info on how any pascal compilers will handle such continues in loops?

Hi JernejL. I think you will never get the answer. As Martin already said the FPC compiler changes between versions and the optimization may perform better on certain machines but not on the others. Also for you information FPC has 4 levels of optimization (0-4):

https://www.freepascal.org/docs-html/prog/progse49.html

i'm still wondering if "with TActor(Actors.Data) do" / or "pActor:=PActor(@Actors.Data);" method is faster..

It's easy you can simply set some benchmark tests as suggested by RayoGlauco.
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Thaddy on March 14, 2018, 12:04:30 pm
@Handoko
Note that there are two things that are important:
- Continue is a procedure... See the documentation (RTFM) https://www.freepascal.org/docs-html/rtl/system/continue.html
- A simple in-place boolean evaluation is usually faster than a procedure call by definition.

So from an algorithmic point of view the first (one less continue) should be faster, although the compiler can optimize it to be about the same code.
BTW: I have hardly ever seen code where continue could not be rewritten in a better way. It is basically a shortcut for lousy lazy programmers.

And if you are curious: always examine the generated assembler as someone mentioned before. And with different optimizations: that can make a huge difference.
But it starts with a good algorithm.
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Mr.Madguy on March 14, 2018, 06:21:50 pm
I mean... Why can you just see, what asm code compiler generates?
Code: Pascal  [Select][+][-]
  1. function Test1:Integer;
  2.   var I:Integer;
  3. begin
  4.   Result := 0;
  5.   for I := 0 to 100 do begin
  6.     if Random(100) >= 50 then begin
  7.       if Random(100) >= 50 then begin
  8.         Inc(Result);
  9.       end;
  10.     end;
  11.   end;
  12. end;
  13.  
  14. function Test2:Integer;
  15.   var I:Integer;
  16. begin
  17.   Result := 0;
  18.   for I := 0 to 100 do begin
  19.     if Random(100) < 50 then Continue;
  20.     if Random(100) < 50 then Continue;
  21.     Inc(Result);
  22.   end;
  23. end;  
  24.  
Find 10 differences. Ignore beginning of procedure Test1, as broken debugger starts disassembling from $004253AF, not from $004253B0, as it should.
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Thaddy on March 14, 2018, 06:31:10 pm
well, do like I do and compile from the command line with -a and subsequently examine the .s file(s)

Don't say that that doesn't work, because that is the real assembler code.
Unless you are on a platform that uses the internal assembler  and do not have an external assembler installed: then you might get confused. Trust me: that's the generated (and as such compilable) assembler code. Instruction by instruction. Internal or external.
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: WooBean on March 14, 2018, 08:12:31 pm
@Mr.Madguy

I mean... Why can you just see, what asm code compiler generates?
Code: Pascal  [Select][+][-]
  1. function Test1:Integer;
  2.   var I:Integer;
  3. begin
  4.   Result := 0;
  5.   for I := 0 to 100 do begin
  6.     if Random(100) >= 50 then begin
  7.       if Random(100) >= 50 then begin
  8.         Inc(Result);
  9.       end;
  10.     end;
  11.   end;
  12. end;
  13.  
  14. function Test2:Integer;
  15.   var I:Integer;
  16. begin
  17.   Result := 0;
  18.   for I := 0 to 100 do begin
  19.     if Random(100) < 50 then Continue;
  20.     if Random(100) < 50 then Continue;
  21.     Inc(Result);
  22.   end;
  23. end;  
  24.  
Find 10 differences. Ignore beginning of procedure Test1, as broken debugger starts disassembling from $004253AF, not from $004253B0, as it should.
Your pascal code of procedure Test1 and procedure Test2 are exactly equivalent and its compiled by FPC and then disassembled code seems too. Conclusion from code efficiency point of view - there is no difference between presented Test1 and Test2. I guess that using "continue" (or "break") is a C-people habit and may lead to errors when chosen to be used in nested iterations.

@Thaddy

well, do like .....
Nothing understood, OK - my personal limits.
@Handoko
Note that there are two things that are important:
- Continue is a procedure... See the documentation (RTFM) https://www.freepascal.org/docs-html/rtl/system/continue.html
- A simple in-place boolean evaluation is usually faster than a procedure call by definition.

So from an algorithmic point of view the first (one less continue) should be faster, although the compiler can optimize it to be about the same code.
BTW: I have hardly ever seen code where continue could not be rewritten in a better way. It is basically a shortcut for lousy lazy programmers.

And if you are curious: always examine the generated assembler as someone mentioned before. And with different optimizations: that can make a huge difference.
But it starts with a good algorithm.
1. "continue" is not a reserved pascal word, we can declare "procedure continue;" and compile it with no problem (I know - a bad idea but possible);
2. local help to Lazarus 1.8.0 describing "continue" is misleading as it states:
Continue jumps to the end of the current repetitive statement. The code between the Continue call and the end of the repetitive statement is skipped. The condition of the repetitive statement is then checked again.
This can be used with For, repeat and While statements.
Note that while this is a procedure, Continue is a reserved word and hence cannot be redefined.


WooBean
 
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Thaddy on March 14, 2018, 08:43:23 pm
1. "continue" is not a reserved pascal word, we can declare "procedure continue;" and compile it with no problem (I know - a bad idea but possible);
Well: https://www.freepascal.org/docs-html/rtl/system/continue.html
More specific:
"Note that while this is a procedure, Continue is a reserved word and hence cannot be redefined."

I don't know what you were smoking, but otherwise file a bug report. Seems pretty obvious to me......<slightly grumpy  >:D >:D>
If it CAN be redefined it is a bug.
And it is a bug against documentation...
See:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$ifdef mswindows}{$apptype console}{$endif}
  3. procedure continue;
  4. begin
  5.   writeln('this is not continue');
  6. end;
  7. var
  8.   i:integer;
  9. begin
  10.   for i := 0 to 3 do
  11.     continue;
  12.   readln; // for feedback.
  13. end.

So you were right on that point. I will file the bug report.
[edit]
Done. Issue 0033429 on Mantis.

Well spotted. But it also means you did not read the manuals....... :o :D :D :D

I hope you will forgive me, but that's how my brain works: if I have read it, it won't go away...
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: JernejL on March 15, 2018, 08:57:11 am
Your pascal code of procedure Test1 and procedure Test2 are exactly equivalent and its compiled by FPC and then disassembled code seems too. Conclusion from code efficiency point of view - there is no difference between presented Test1 and Test2. I guess that using "continue" (or "break") is a C-people habit and may lead to errors when chosen to be used in nested iterations.

This is good news and bad news - So it's good that compiler / optimization does its job, but sadly i can't benefit to switching to a specific style to get extra few instructions :)
 
This is what i was wondering the most, thanks for clarifying this.
 
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Thaddy on March 15, 2018, 09:15:15 am
There are plenty of cases where it matters and the compiler can not find the shortest code path just not in this case.
E.g. at this point in time the compiler is not very good at loop optimizations and not capable of bringing loop variables that do not change inside the loop outside of the loop.
So you still need to optimize the algorithm first. That is always the case. And for any compiler, not just FPC. And you always need to examine the generated assembler to see if it actually matters.
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: egsuh on March 15, 2018, 01:18:08 pm
Regarding "continue",  I find "continue" useful when the logic requires many nested if..else structures. For example,

Code: Pascal  [Select][+][-]
  1. if cond1 then
  2. else begin
  3.     //  do something;
  4.     if cond2 then
  5.     else begin
  6.          // do other things;
  7.          if cond3 then
  8.          else begin
  9.               // do something more
  10.               //... and so on.
  11.          end;
  12.     end;
  13.  end;
  14.  
         

I can use "continue" instead of if..else structure as following.

Code: Pascal  [Select][+][-]
  1. if cond1 then Continue;
  2. // do something
  3.  
  4. if cond2 then continue;
  5. // do other things;
  6.  
  7. if cond3 then continue;
  8. // do something more
  9. //... and so on.
  10.  


It's for readability instead of performance.
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Thaddy on March 15, 2018, 01:25:14 pm
Well, I must have an eyesight problem because such coding style is horrible....
(Anyway Michael fixed the documentation bug)
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Paul_ on March 15, 2018, 03:44:18 pm
@egsuh

Code: Pascal  [Select][+][-]
  1. then else

It makes no sense to me, why you don't use logical operators instead of such unreadable constructions?
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Handoko on March 15, 2018, 04:54:41 pm
I prefer not(cond), which looks better in my eyes:

Code: Pascal  [Select][+][-]
  1.   if not(cond1) then
  2.   begin
  3.     //  do something;
  4.     if not(cond2) then
  5.     begin
  6.       // do other things;
  7.       if not(cond3) then
  8.       begin
  9.         // do something more
  10.         //... and so on.
  11.       end;
  12.     end;
  13.   end;
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Thaddy on March 15, 2018, 05:46:59 pm
Yes. And it is probably faster too.
Also note begin/end doesn't generate instructions by itself. That also seems to confuse OP. begin begin begin end end end is the same as begin end
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: egsuh on March 16, 2018, 05:58:40 am
I just wanted to show the "nesting" problem.

Let's see some other case.

Code: Pascal  [Select][+][-]
  1. for i := 0 to N do beign
  2.     if cond1 then begin
  3.          State := 1;
  4.          Var1 := afunction(state);
  5.     end
  6.     else begin
  7.         //  do something;
  8.  
  9.         if cond2 then begin
  10.             State := 2;
  11.             Var2 := afunction(state);
  12.         end  
  13.         else begin
  14.              //  Do others
  15.  
  16.             if cond3 then begin
  17.                  State := 3;
  18.                  Var1 := anotherfunction(State);
  19.                  Var2 := afunction(State3);
  20.             end
  21.             else begin
  22.                   // Do more things
  23.             end
  24.        end
  25.    end
  26. end;
  27.  

We can write this as:

Code: Pascal  [Select][+][-]
  1. for i := 0 to N do beign
  2.      if cond1 then begin
  3.          State := 1;
  4.          Var1 := afunction(state);
  5.          Continue;
  6.     end ;
  7.  
  8.      //  do something;
  9.  
  10.      if cond2 then begin
  11.          State := 2;
  12.          Var2 := afunction(state);
  13.          Continue;
  14.      end ;
  15.  
  16.      //  Do others
  17.  
  18.      if cond3 then begin
  19.           State := 3;
  20.           Var1 := anotherfunction(State);
  21.           Var2 := afunction(State);
  22.           Continue;
  23.      end;
  24.  
  25.      // Do more things
  26. end;
  27.  

And think of cases where are rather lot of codes in the commented part of "do something", "do others", etc. The same with Exit.
Title: Re: Lazarus / delphi loop efficiency: continue or begin..end?
Post by: Thaddy on March 16, 2018, 09:22:58 am
Code: Pascal  [Select][+][-]
  1. for i := 0 to N do
  2.    case condition of
  3.      cond1:begin
  4.              State := 1;
  5.              Var1 := afunction(state);
  6.            end;
  7.      cond2:begin
  8.              State := 2;
  9.              Var2 := afunction(state);        
  10.            end ;
  11.      cond3:begin
  12.              State := 3;
  13.              Var1 := anotherfunction(State);
  14.              Var2 := afunction(State);
  15.            end;
  16.     end;
  17.  

Looks much nicer and is faster
TinyPortal © 2005-2018