Lazarus

Free Pascal => Beginners => Topic started by: Joanna on April 18, 2025, 02:57:59 pm

Title: [solved] looping direction controlled by flag
Post by: Joanna on April 18, 2025, 02:57:59 pm
hi I'm trying to make a function that can iterate through an array with direction controlled by a boolean flag. so far i have this but it doesn't compile
Code: Pascal  [Select][+][-]
  1. FUNCTION TCASCADING_FLOWPANEL.GET_THE_CONTROL(CONST IS_FIRST:BOOLEAN):TCONTROL;
  2.          VAR X:INTEGER;
  3. BEGIN
  4. IF IS_FIRST
  5.    THEN FOR X:= LOW(AR_CONTROLS) TO HIGH(AR_CONTROLS) DO
  6.             IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X])
  7.    ELSE FOR X:= HIGH(AR_CONTROLS) DOWNTO LOW(AR_CONTROLS) DO
  8.             IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X]);
  9. ERROR_HALT('FUNCTION TCASCADING_FLOWPANEL.GET_THE_CONTROL');
  10. END;

does anyone have any idea of how to do this?
Title: Re: looping direction controlled by flag
Post by: MarkMLl on April 18, 2025, 03:14:47 pm
What error message are you getting? Also note that you've got a dangling else in the middle of it.

MarkMLl
Title: Re: looping direction controlled by flag
Post by: Thaddy on April 18, 2025, 03:43:47 pm
@Joanna
I am pretty sure that is just your capslock being stuck 8-)
Title: Re: looping direction controlled by flag
Post by: Joanna on April 18, 2025, 04:08:20 pm
The error is illegal assignment to a loop variable on the line with the else. In other words it seems to think the second loop is the else condition for the if statement inside the loop.. Definitely wrong
Title: Re: looping direction controlled by flag
Post by: MarkMLl on April 18, 2025, 04:42:08 pm
The error is illegal assignment to a loop variable on the line with the else. In other words it seems to think the second loop is the else condition for the if statement inside the loop.. Definitely wrong

Let's try to rearrange it a bit.

Code: Pascal  [Select][+][-]
  1. FUNCTION TCASCADING_FLOWPANEL.GET_THE_CONTROL(CONST IS_FIRST:BOOLEAN):TCONTROL; VAR X:INTEGER;
  2.  
  3. BEGIN
  4.     IF IS_FIRST THEN
  5.         FOR X:= LOW(AR_CONTROLS) TO HIGH(AR_CONTROLS) DO
  6.             IF PROVIDES_SQL(AR_CONTROLS[X]) THEN
  7.                 EXIT(AR_CONTROLS[X])
  8.             ELSE
  9.                 FOR X:= HIGH(AR_CONTROLS) DOWNTO LOW(AR_CONTROLS) DO
  10.                     IF PROVIDES_SQL(AR_CONTROLS[X]) THEN
  11.                         EXIT(AR_CONTROLS[X]);
  12.     ERROR_HALT('FUNCTION TCASCADING_FLOWPANEL.GET_THE_CONTROL');
  13. END;
  14.  

Can you see it now?

MarkMLl




Title: Re: looping direction controlled by flag
Post by: Josh on April 18, 2025, 04:42:41 pm
your trying to use same x variable in a loop that isalreadyin an x loop
reformatting inyour CAPS style, hopefully helps

Code: Pascal  [Select][+][-]
  1. IF IS_FIRST THEN
  2.   FOR X:= LOW(AR_CONTROLS) TO HIGH(AR_CONTROLS) DO
  3.     IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X])
  4.     ELSE
  5.       FOR X:= HIGH(AR_CONTROLS) DOWNTO LOW(AR_CONTROLS) DO  // <<- You creating a new x foor loop,while still in thef irst x loop
  6.         IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X]);        

If the below code is what your after,by adding a ;
Code: Pascal  [Select][+][-]
  1. IF IS_FIRST THEN FOR X:= LOW(AR_CONTROLS) TO HIGH(AR_CONTROLS) DO IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X]);       // added;
  2. ELSE FOR X:= HIGH(AR_CONTROLS) DOWNTO LOW(AR_CONTROLS) DO IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X]);
  3.          
Or easier to read IMO, as ZORAN suggests

Code: Pascal  [Select][+][-]
  1. IF IS_FIRST THEN
  2. BEGIN // GOING UP
  3.   FOR X:= LOW(AR_CONTROLS) TO HIGH(AR_CONTROLS) DO
  4.   BEGIN
  5.     IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X]);
  6.   END;
  7. END
  8. ELSE
  9. BEGIN  // GOING DOWN
  10.   FOR X:= HIGH(AR_CONTROLS) DOWNTO LOW(AR_CONTROLS) DO
  11.   BEGIN
  12.     IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X]);
  13.   END;
  14. END;
Title: Re: looping direction controlled by flag
Post by: Zoran on April 18, 2025, 05:16:26 pm
does anyone have any idea of how to do this?

This is not Python, the "else" is always connected to the last "if" before it. See Mark's post, it should make it very clear for you.
Putting begin-end where appropriate certainly solves this.

Then, you are lucky that you used the same variable in both loops (as Josh spotted) which turned it to compile time error, not only semantic error which could go unnoticed.

Make a habit of using begin-end with if statement.
Title: Re: looping direction controlled by flag
Post by: MarkMLl on April 18, 2025, 06:12:27 pm
This is not Python, the "else" is always connected to the last "if" before it. See Mark's post, it should make it very clear for you.
Putting begin-end where appropriate certainly solves this.

Steady on: I don't think Joanna knows Python (and if she does, she likes it less than any of us). I'm hoping that she gives me an opportunity to work through what she's done (when compared with what she /thinks/) she's done in some detail, so that she doesn't fall into this trap again.

MarkMLl
Title: Re: looping direction controlled by flag
Post by: Joanna on April 18, 2025, 11:15:07 pm
thanks for the replies. it was indeed getting confused by the THEN inside the loop. the redundancy still bothers me but how about this?
Code: Pascal  [Select][+][-]
  1. FUNCTION TCASCADING_FLOWPANEL.GET_THE_CONTROL(CONST IS_FIRST:BOOLEAN):TCONTROL;
  2.          VAR X:INTEGER;
  3. BEGIN
  4. IF IS_FIRST
  5.    THEN FOR X:= LOW(AR_CONTROLS) TO HIGH(AR_CONTROLS) DO
  6.             IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X]);
  7. IF NOT IS_FIRST
  8.    THEN FOR X:= HIGH(AR_CONTROLS) DOWNTO LOW(AR_CONTROLS) DO
  9.             IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X]);
  10. ERROR_HALT('FUNCTION TCASCADING_FLOWPANEL.GET_THE_CONTROL');
  11. END;    
it seems that there is no way to choose which loop to execute for the same line of code that follows...
Title: Re: looping direction controlled by flag
Post by: Josh on April 19, 2025, 12:30:30 am
Add a Y var for main loop, assign x value according to direction, and check in loop to inc or dec x

Note this harder to follow, and will be slower..... Y for loop will be optimized as value likely store in register,but the inc/dec of x may not be, plus addition of check code inside loop

Something like
Code: Pascal  [Select][+][-]
  1. if IS_FIRST then x:=low(AR_CONTROLS) else x:=high(AR_CONTROLS);    // set x initial value
  2. for y:=low(AR_CONTROLS) to high(AR_CONTROLS) do
  3. begin
  4.   if PROVIDES_SQL(AR_CONTROLS[X])THEN Exit(AR_CONTROLS[X]);
  5.   if IS_FIRST then inc(x) else dec(x); // adjust x based on direction
  6. end;
  7. ERROR_HALT('FUNCTION TCASCADING_FLOWPANEL.GET_THE_CONTROL');      
Title: Re: looping direction controlled by flag
Post by: TBMan on April 19, 2025, 01:15:12 am
I would do something like this (in semi psuedo code):
(I prefer to use begins and ends even though you don't always have to. It makes for an easier read. And I try to remember
to label the "ends" to match the "begins"

Code: Pascal  [Select][+][-]
  1.  
  2. var
  3.  X,GotIt:integer;
  4.  
  5. if IsFirst then
  6.   begin
  7.      for x := low to high do
  8.        begin
  9.          if condition then
  10.             begin
  11.               Gotit := X;
  12.               break;
  13.             end; // end if
  14.        end; // for
  15.   end
  16.   else // IsFirst
  17.   begin
  18.       for x := high to low do
  19.       begin
  20.          if condition then
  21.             begin
  22.                 GotIt := x;
  23.                 break;
  24.            end; // endIf
  25.      end; // for
  26.   end; // else  
  27. result := Whatever(GotIt);
Title: Re: looping direction controlled by flag
Post by: TRon on April 19, 2025, 05:28:51 am
Add a Y var for main loop, assign x value according to direction, and check in loop to inc or dec x
That was a nudge in the good direction but did you know that there exist delta airlines and they use planes that can fly in different directions and make use of planes that can have other ranges ? While that is good to know that you could also choose for another airline ?

feeling a bit cryptic today...  :)

Title: Re: looping direction controlled by flag
Post by: cdbc on April 19, 2025, 07:46:42 am
Hi
Another possibility would be to utilize 'case', like this:
Code: Pascal  [Select][+][-]
  1. var x: integer;
  2. begin
  3.   case IsFirst of
  4.     false: begin
  5.              for x:= ControlCount-1 downto 0 do
  6.                if Controls[x].Name = 'Memo1' then exit(Controls[x]);
  7.            end;
  8.     true: begin
  9.             for x:= 0 to ControlCount-1 do
  10.               if Controls[x].Name = 'Edit1' then exit(Controls[x]);
  11.           end
  12.   end;
  13.   Result:= nil;
  14.   fPresenter.Provider.NotifySubscribers(prStatus,nil,Str2Pch('(!) Attention: Control was not found! '));
  15. end;
  16.  
I hope you get the gist of the algorithm, 'cause I really don't wanna mess with your caps-locked-code...
Regards Benny
Title: Re: looping direction controlled by flag
Post by: Josh on April 19, 2025, 08:28:24 am
Using Delta Airlines. Avoids the comparison check in loop

add A DeltaAirlines Var
Code: Pascal  [Select][+][-]
  1. DeltaAirlines:=1; // DeltaAirlines is Going to its Destination
  2. x:=low(AR_CONTROLS); // set x initial value
  3. if Not IS_FIRST then
  4. begin
  5.   DeltaAirlines:=-1; // DeltaAirlines is going its Origin
  6.   x:=high(AR_CONTROLS); // set x initial value
  7. end;
  8. for y:=low(AR_CONTROLS) to high(AR_CONTROLS) do
  9. begin
  10.   if PROVIDES_SQL(AR_CONTROLS[X])THEN Exit(AR_CONTROLS[X]);
  11.   x:=x+DeltaAirlines; // adjust x based on DeltaAirlines direction
  12. end;
  13. ERROR_HALT('FUNCTION TCASCADING_FLOWPANEL.GET_THE_CONTROL');

And as function

Code: Pascal  [Select][+][-]
  1. FUNCTION TCASCADING_FLOWPANEL.GET_THE_CONTROL(CONST IS_FIRST:BOOLEAN):TCONTROL;
  2. VAR X,Y,DELTA_AIRLINES:INTEGER; // ADD EXTRA VARS
  3. BEGIN
  4.   DELTA_AIRLINES:=1; // DELTA_AIRLINES IS GOING TO ITS DESTINATION
  5.   X:=LOW(AR_CONTROLS); // SET X INITIAL VALUE
  6.   IF NOT IS_FIRST THEN
  7.   BEGIN
  8.     DELTA_AIRLINES:=-1; // DELTA_AIRLINES IS GOING TO ITS ORIGIN
  9.     X:=HIGH(AR_CONTROLS); // SET X INITIAL VALUE
  10.   END;
  11.   FOR Y:=LOW(AR_CONTROLS) TO HIGH(AR_CONTROLS) DO
  12.   BEGIN
  13.     IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X]);
  14.     X:=X+DELTA_AIRLINES; // ADJUST X BASED ON DELTA_AIRLINES DIRECTION
  15.   END;
  16.   ERROR_HALT('FUNCTION TCASCADING_FLOWPANEL.GET_THE_CONTROL');
  17. END;    
Title: Re: looping direction controlled by flag
Post by: TRon on April 19, 2025, 09:03:34 am
Bravo Josh.

With a bit of abstraction it might even end up something like
Code: Pascal  [Select][+][-]
  1. var
  2.   Flight  : TIterate;
  3.   Airport : sizeint;
  4. begin
  5.   if isNormalRoute
  6.    // The following can be abstracted as well, f.e. by adding a direction (delta) parameter
  7.    then Flight := TIterate.Create(low(Destinations), high(Destinations))
  8.   else Flight := TIterate.Create(high(Destinations), low(Destinations));
  9.  
  10.   while Flight.Next(Airport) do
  11.     if NeedToLand(Destinations[Airport])
  12.       then exit(Destinations[Airport]);
  13. end;
  14.  

Not the fastest solution to use a self made iterator but certainly pleasant to read/understand. The omitted iterator record uses the same mechanism as per Josh's example.
Title: Re: looping direction controlled by flag
Post by: Josh on April 19, 2025, 09:42:47 am
indeed,
adds more code but function can be tided up,
even the directiion can be set in the create

Code: Pascal  [Select][+][-]
  1. TControlIterator = class
  2.   private
  3.     F_Controls: TArray<TControl>;
  4.     F_Index: Integer;
  5.     F_Step: Integer;
  6.     F_Low, F_High: Integer;
  7. ........
  8. ........
  9. constructor TControlIterator.Create(const Controls: TArray<TControl>; IsFirst: Boolean);
  10. begin
  11.   F_Controls := Controls;
  12.   F_Low := Low(Controls);
  13.   F_High := High(Controls);
  14.  
  15.   if IsFirst then
  16.   begin
  17.     F_Index := F_Low;  // Start from the beginning
  18.     F_Step := 1;      // Move forward
  19.   end
  20.   else
  21.   begin
  22.     F_Index := F_High; // Start from the end
  23.     F_Step := -1;     // Move backward
  24.   end;
  25. end;                  
  26.  
  27. .......
  28.  
  29.  

and function
Code: Pascal  [Select][+][-]
  1. function GetTheControl(const IsFirst: Boolean): TControl;
  2. var
  3.   Flight: TControlIterator;
  4.   Cntrl: TControl;
  5. begin
  6.   Flight := TControlIterator.Create(AR_CONTROLS, IsFirst);
  7.   try
  8.     while Flight.HasNext do
  9.     begin
  10.       Cntrl := Flight.Next;
  11.       if Provides_SQL(Cntrl) then  Exit(Cntrl);
  12.     end;
  13.   finally
  14.     Flight.Free;
  15.   end;
  16.   Error_Halt('No matching control found.');
  17. end;
  18. end;  
Title: Re: looping direction controlled by flag
Post by: Joanna on April 19, 2025, 07:07:08 pm
Hi
Another possibility would be to utilize 'case', like this:
Code: Pascal  [Select][+][-]
  1. var x: integer;
  2. begin
  3.   case IsFirst of
  4.     false: begin
  5.              for x:= ControlCount-1 downto 0 do
  6.                if Controls[x].Name = 'Memo1' then exit(Controls[x]);
  7.            end;
  8.     true: begin
  9.             for x:= 0 to ControlCount-1 do
  10.               if Controls[x].Name = 'Edit1' then exit(Controls[x]);
  11.           end
  12.   end;
  13.   Result:= nil;
  14.   fPresenter.Provider.NotifySubscribers(prStatus,nil,Str2Pch('(!) Attention: Control was not found! '));
  15. end;
  16.  
I hope you get the gist of the algorithm, 'cause I really don't wanna mess with your caps-locked-code...
Regards Benny
Or this
Code: Pascal  [Select][+][-]
  1.  FUNCTION TCASCADING_FLOWPANEL.GET_THE_CONTROL(CONST IS_FIRST:BOOLEAN):TCONTROL;
  2.          VAR X:INTEGER;
  3. BEGIN
  4. CASE IS_FIRST OF
  5.         TRUE: FOR X:= LOW(AR_CONTROLS) TO HIGH(AR_CONTROLS) DO
  6.                          IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X]);
  7.          FALSE: FOR X:= HIGH(AR_CONTROLS) DOWNTO LOW(AR_CONTROLS) DO
  8.                            IF PROVIDES_SQL(AR_CONTROLS[X])THEN EXIT(AR_CONTROLS[X]);
  9.           END;
  10. ERROR_HALT('FUNCTION TCASCADING_FLOWPANEL.GET_THE_CONTROL');
  11. END;  
Title: Re: looping direction controlled by flag
Post by: cdbc on April 19, 2025, 07:14:48 pm
Hi Joanna
Yup, I think you've got it =^
I'll just put on my shades  8), so I don't get an 'Eye-Sore'...  :D
Regards Benny
Title: Re: looping direction controlled by flag
Post by: 440bx on April 19, 2025, 08:08:37 pm
For some reason, Pascal code looks horrible in all uppercase.
Title: Re: looping direction controlled by flag
Post by: Joanna on April 20, 2025, 01:15:47 pm
cdbc i liked the idea of the case because even though my
two if statements could never both be true  its still sort of sloppy to call both of them. The case gives less ambiguity in what will happen if thats the correct term...
Title: Re: [solved] looping direction controlled by flag
Post by: cdbc on April 20, 2025, 01:20:04 pm
Hi Joanna
Yup, I think 'case' makes for clear code.
Regards Benny
TinyPortal © 2005-2018