Recent

Author Topic: Back in cycle level  (Read 1419 times)

Jake012345

  • Sr. Member
  • ****
  • Posts: 258
  • 'The knowledge is the key.'
    • FPCProjectShare
Back in cycle level
« on: July 10, 2020, 12:24:16 am »
Hello!

I need to leave a cycle in a cycle but when I use Break/exit, that leave the whole cycle / procedure.

But I need:

Code: Pascal  [Select][+][-]
  1. procedure MyProcedure;
  2.  var a,b,c:integer;
  3. begin
  4.   for a:=0 to 10 do
  5.    @
  6.     for b:=0 to 10 do begin
  7.      c:=StrToInt(inputbox());
  8.      if c=3 then BackTo('@');
  9.    end;
  10. end;
  11.  
  12.  

I haeard about 'goto' but I couldn't find anything that can help me and working :\
Is there a way to do that?
« Last Edit: July 10, 2020, 12:30:41 am by Jake012345 »
Check my ProjectShare site and share your content: FPCShare

jamie

  • Hero Member
  • *****
  • Posts: 3537
Re: Back in cycle level
« Reply #1 on: July 10, 2020, 12:33:30 am »
Look at BREAK and CONTINUE..

The only true wisdom is knowing you know nothing

winni

  • Hero Member
  • *****
  • Posts: 1813
Re: Back in cycle level
« Reply #2 on: July 10, 2020, 12:42:26 am »
Hi!

Use the whole syntax that Pascal offers:

Code: Pascal  [Select][+][-]
  1. procedure MyProcedure;
  2.  var a,b,c:integer;
  3. begin
  4.   for a:=0 to 10 do
  5.   begin    
  6.    b := 0; c := 0;
  7.   while (b  <=10) and (c<>3) do begin
  8.      c:=StrToInt(inputbox());
  9.      inc(b);
  10.    end; // while
  11.  end; // for
  12. end;
  13.  

Winni
« Last Edit: July 10, 2020, 12:44:27 am by winni »

Warfley

  • Sr. Member
  • ****
  • Posts: 303
Re: Back in cycle level
« Reply #3 on: July 10, 2020, 01:41:25 am »
Sadly pascal does not have named loops like Ada, but in your case break should work, because it breaks the most inner loop (so your b loop):
Code: Pascal  [Select][+][-]
  1. procedure MyProcedure;
  2.  var a,b,c:integer;
  3. begin
  4.   for a:=0 to 10 do
  5.     for b:=0 to 10 do begin
  6.      c:=StrToInt(inputbox());
  7.      if c=3 then Break;
  8.    end;
  9. end;
Other possibility: merge loops, there is no need for 2 for loops here:
Code: Pascal  [Select][+][-]
  1. a := 0;
  2. b := 0;
  3. while a <= 10 do
  4. begin
  5.   Inc(b);
  6.   if b > 10 then Inc(a)
  7.   else
  8.   begin
  9.     c := StrToInt(inputbox())
  10.     if c = 3 then b := 0;
  11.   end;
  12. end;

If you want to use goto:
Code: Pascal  [Select][+][-]
  1. var a,b,c: Integer;
  2. label bLoop;
  3. begin
  4.   for a := 0 to 10 do
  5.   begin
  6. bLoop:
  7.     for b := 0 to 10 do
  8.     begin
  9.       c := StrToInt(inputbox());
  10.       if c = 3 then goto bLoop;
  11.     end;
  12.   end;
  13. end;

PascalDragon

  • Hero Member
  • *****
  • Posts: 2138
  • Compiler Developer
Re: Back in cycle level
« Reply #4 on: July 10, 2020, 09:17:40 am »
I need to leave a cycle in a cycle but when I use Break/exit, that leave the whole cycle / procedure.

Exit leaves the routine, Break leaves the innermost cycle it is part of.

winni

  • Hero Member
  • *****
  • Posts: 1813
Re: Back in cycle level
« Reply #5 on: July 10, 2020, 01:49:59 pm »
@Warfley

I dont want to talk about that military-Star-Wars-Language ADA which has now grown to such a monster that it is compatible to nearly everything.

The second example is wrong because every time c hits the condition a is not incremented anymore. There might be conditions that run into an endless loop.

The third example is goto: Goto Basic.

Winni

Blaazen

  • Hero Member
  • *****
  • Posts: 2919
  • POKE 54296,15
    • Eye-Candy Controls
Re: Back in cycle level
« Reply #6 on: July 10, 2020, 02:00:29 pm »
Alternative with nested procedure:
Code: Pascal  [Select][+][-]
  1. procedure MyProcedure;
  2.  
  3.   procedure MyNestedProc;
  4.   var b,c:integer;
  5.   begin
  6.     for b:=0 to 10 do begin
  7.       c:=StrToInt(inputbox());
  8.       if c=3 then  break;
  9.     end;
  10.   end;
  11.  
  12. var a: integer;
  13. begin
  14.   for a:=0 to 10 do
  15.     MyNestedProc;
  16. end;      
Lazarus 2.1.0 r63881 FPC 3.3.1 r40507 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

MarkMLl

  • Hero Member
  • *****
  • Posts: 1232
Re: Back in cycle level
« Reply #7 on: July 10, 2020, 02:26:30 pm »
Code: Pascal  [Select][+][-]
  1. procedure MyProcedure;
  2.  var a,b,c:integer;
  3. begin
  4.   for a:=0 to 10 do
  5.     for b:=0 to 10 do begin
  6.      c:=StrToInt(inputbox());
  7.      if c=3 then Break;
  8.    end;
  9. end;

Remember that the value of b becomes undefined if the break is taken.

MarkMLl

Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.

Warfley

  • Sr. Member
  • ****
  • Posts: 303
Re: Back in cycle level
« Reply #8 on: July 10, 2020, 02:43:57 pm »
Just thought about it again, Break does not work here, because then A will be incremented before the b loop is started again. In the original post, he wants to jump before the b loop, without incrementing a.

I've also seen that my "one" loop solution has some bugs. So I think there are about two valid possibilities:
1. While loop
Code: Pascal  [Select][+][-]
  1.     a := 0;
  2.     b := 0;
  3.     while a <= 10 do
  4.     begin
  5.       c := StrToInt(inputbox())
  6.       if c = 3 then b := 0;
  7.       Inc(b);
  8.       if b > 10 then
  9.       begin
  10.         b := 0;
  11.         Inc(a);
  12.       end;
  13.     end;
or using a structure similar to the original post
Code: Pascal  [Select][+][-]
  1. a := 0;
  2. while a <= 10 do begin
  3.   b := 0;
  4.   while b <= 10 do begin
  5.     c:=StrToInt(inputbox());
  6.     Inc(b);
  7.     if c=3 then b:=0;
  8.   end;
  9.   Inc(a);
  10. end;

2. Goto:
Code: Pascal  [Select][+][-]
  1. var a,b,c: Integer;
  2. label bLoop;
  3. begin
  4.   for a := 0 to 10 do begin
  5. bLoop:
  6.     for b := 0 to 10 do begin
  7.       c := StrToInt(inputbox());
  8.       if c = 3 then goto bLoop;
  9.     end;
  10.   end;
  11. end;

And now a maybe unpopular oppinion, I would go with the goto variant, because the code is 1. shorter and 2. easier to understand then the while loops (case in point, my first version of the while loop was actually buggy). And as long as it leads to better readable code, there is nothing wrong about goto
« Last Edit: July 10, 2020, 02:47:06 pm by Warfley »

winni

  • Hero Member
  • *****
  • Posts: 1813
Re: Back in cycle level
« Reply #9 on: July 10, 2020, 03:02:37 pm »
Hi!

I have show the clear solution above.

Advantage 1: No errors
Advantage 2: pure pascal without  goto or break
Disadvantage: One must understand two condiditions connected with an AND

So again:
Code: Pascal  [Select][+][-]
  1.     procedure MyProcedure;
  2.      var a,b,c:integer;
  3.     begin
  4.       for a:=0 to 10 do
  5.       begin    
  6.        b := 0; c := 0;
  7.       while (b  <=10) and (c<>3) do begin
  8.          c:=StrToInt(inputbox());
  9.          inc(b);
  10.        end; // while
  11.      end; // for
  12.     end;
  13.      

Winni

Warfley

  • Sr. Member
  • ****
  • Posts: 303
Re: Back in cycle level
« Reply #10 on: July 10, 2020, 03:08:47 pm »
Hi!

I have show the clear solution above.
Except that this has the same error I did in my first post also, if c is 3, the loop is broken and the a loop will continue which will increase a.

Imagine the following case, inputbox always returns 3. In the goto example (which is basically what the original post did), this would result in an infinite loop, in your example this would result in exactly 11 iterations and then the procedure would finish.

Otherwise, I would choose the break version, because for loops are imho easier to read then while loops.

Also, what does "pure pascal" mean, aren't break and goto parts of the pascal language?
« Last Edit: July 10, 2020, 03:12:01 pm by Warfley »

AlanTheBeast

  • Jr. Member
  • **
  • Posts: 73
Re: Back in cycle level
« Reply #11 on: July 10, 2020, 03:11:49 pm »
Avoid goto.  Yes, you can have 'tighter' code.  But it ages badly over time.  Why many SQ policies forbid it entirely in HOL.

Recently revised a rather long bit of code that goes through up to 6 states searching for an output (tighter to looser rules) and it was tempting to use goto to get out of the central portion to outskirts of the function.  But, looking at the gen'd assembler it wasn't worth it at all.

Continue/Break are your friends as others mention.

440bx

  • Hero Member
  • *****
  • Posts: 2001
Re: Back in cycle level
« Reply #12 on: July 10, 2020, 03:12:55 pm »
2. Goto:
Code: Pascal  [Select][+][-]
  1. var a,b,c: Integer;
  2. label bLoop;
  3. begin
  4.   for a := 0 to 10 do begin
  5. bLoop:
  6.     for b := 0 to 10 do begin
  7.       c := StrToInt(inputbox());
  8.       if c = 3 then goto bLoop;
  9.     end;
  10.   end;
  11. end;

And now a maybe unpopular oppinion, I would go with the goto variant, because the code is 1. shorter and 2.
but.. it has a "small" problem: it causes an infinite loop because "a" is never incremented.  OTH, the solution you suggested using "break" doesn't and seems to solve the OP's problem satisfactorily.

And as long as it leads to better readable code, there is nothing wrong about goto
And _no_ infinite loops. <chuckle>

ETA:
"never" after c = 3

« Last Edit: July 10, 2020, 03:15:35 pm by 440bx »
FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

Warfley

  • Sr. Member
  • ****
  • Posts: 303
Re: Back in cycle level
« Reply #13 on: July 10, 2020, 03:18:11 pm »
Avoid goto.  Yes, you can have 'tighter' code.  But it ages badly over time.  Why many SQ policies forbid it entirely in HOL.
Nah, goto is only bad if it is used badly, simple as that. While it's true that 99% of the time goto is misused, here we have a case where it is better than any other use (as already discussed, break and continue do not fit here), where it actually improves the code (from a readability point of view, I don't care about the produced assembly, this is the job of the compiler not mine)

but.. it has a "small" problem: it causes an infinite loop because "a" is never incremented.  OTH, the solution you suggested using "break" doesn't and seems to solve the OP's problem satisfactorily.
Which is exactly the behaviour requested in the original post... If he wants code that can loop infinetly often that is none of my problem, maybe he has reasons for this, maybe it's a logical error on his side, he requested how to solve this problem so I think we should give him the *correct* solution (with respect to his question) and not the thing we think he wants. Becaus I don't know about you, but I don't trust my mind reading skills that far that I can read minds through an internet forum
« Last Edit: July 10, 2020, 03:19:52 pm by Warfley »

AlanTheBeast

  • Jr. Member
  • **
  • Posts: 73
Re: Back in cycle level
« Reply #14 on: July 10, 2020, 03:24:07 pm »
Hi!

I have show the clear solution above.
Except that this has the same error I did in my first post also, if c is 3, the loop is broken and the a loop will continue which will increase a.

Imagine the following case, inputbox always returns 3. In the goto example (which is basically what the original post did), this would result in an infinite loop, in your example this would result in exactly 11 iterations and then the procedure would finish.

Otherwise, I would choose the break version, because for loops are imho easier to read then while loops.

Also, what does "pure pascal" mean, aren't break and goto parts of the pascal language?

With nested loops, breaking out may require flags be set

Code: Pascal  [Select][+][-]
  1.            if break_condition then begin brflag := true; break end;
  2.  

Then use brflag to get out of the outer loop and so on.  (break doesn't "break" begin/end closures, only controlled loops (while, for, repeat).

Some code I recently revised (which doesn't use break, but comes to the same thing...)
Code: Pascal  [Select][+][-]
  1.        // long winded code not shown here ... but you can assume the Repeat's are there...
  2.                                 With P^ do
  3.                                         begin
  4.                                                 Case State of
  5.                                                         0: found := (FPStat=PartialPlay) and (Playtime<TLim);
  6.                                                         1: found := (FPStat=NeverPlayed) and NOT TooNew and (Playtime<TLim);
  7.                                                         2: found := (FPStat<>PlayedThisSession) and NOT TooNew and (Playtime<TLim);
  8.                                                         3: found := (FPStat<>PlayedThisSession) and (Playtime<TLim);
  9.                                                         4: found := Playtime<TLim;
  10.                                                         5: found := true;  // unlikely but need a guaranteed way out.
  11.                                                 end;
  12.                                         end;
  13.                         Until found or (Rc >= GC[Gr]);
  14.                 Until found or (Tlim>now);
  15.         Until found;
  16.         exit(P)
  17. END;
  18.  

Loop control (For, While, Repeat) is an implementation choice for functional, efficient, readable (in that order) code.

I personally will use Repeat more than While if it makes sense ... but that isn't always the most readable code.

And for is for a strict range of choice (even if the range is defined by variables) whereas the others are for things that change state inside the loop(s).

Goto is in the original Wirth Pascal manual but should not be used. 
FPC requires a {$GOTO ON} and label pre-declaration.  AVOID.
Break/Continue are add ons (necessary) to the original language.
« Last Edit: July 10, 2020, 03:33:19 pm by AlanTheBeast »

 

TinyPortal © 2005-2018