how to exit a double for next loop ?

Community Forums/General Help/how to exit a double for next loop ?

RemiD(Posted 2016) [#1]
Hello, :)

I am curious which method you use to exit a double for next loop ?
In the past i used "Goto .Line", it worked well.
Then i learned about "Exit", and it worked well for unique for next loop.
But when you want to exit a double for next loop, using "Exit" is not enough because it only exits the current for next loop...
See :
Graphics(640,480,32,2)

Global ncount%
Global nncount
For n% = 1 To 10 Step 1
 ncount = ncount + 1
 For nn% = 1 To 10 Step 1
  nncount = nncount + 1
  If( nncount => 5 )
   ;Exit
   ;Goto LineEndProcedure 
  EndIf
 Next
 If( ncount => 5 )
  ;Exit
  ;Goto LineEndProcedure
 EndIf
Next
.LineEndProcedure
DebugLog("ncount = "+ncount)
DebugLog("nncount = "+nncount)

WaitKey()

End()


"Goto .Line" works well but some say it is bad to use this (i don't agree, if you know how your code flows, and you know how to debug your code, there is no problem)

Is there another method to achieve the same thing ? (exit a double for next loop)

Thanks,


Zethrax(Posted 2016) [#2]
Generally I use a flag variable.

exit_flag = False
For y = 1 To 10
	For x = 1 To 10
		If x = 5 Then exit_flag = True : Exit
	Next
	If exit_flag Then Exit
Next

Print x

WaitKey
End


Using Goto to jump out of a loop would probably lead to the resources for the loop not being freed, resulting in memory leaks and other issues. It's likely a prime example of why the use of Goto is discouraged.


grable(Posted 2016) [#3]
Im afraid not. Using a label and goto is the only way for Blitz3D and BlitzPlus.

BlitzMax has this:
#top
For y = 0 To 480-1
	For x = 0 To 640-1
		If y = 240 Then Exit top
	Next
Next
which isnt much different than putting a label at the bottom and using a goto instead.

Turns out i remembered wrong ;) At least While/Repeat has it. For really should have this too!

Dont fuss about using Gotos. Anyone who says they are bad are simply parroting a paper from the 1968 in a time where people used ONLY gotos and line numbers for flow control.
IE it doesnt apply today, unless perhaps for complete beginners.

EDIT: I was too slow ;) The flag thing works too. But if your in tight loops, having to add an additional compare might make things a tad slower.


RemiD(Posted 2016) [#4]
Thanks for your examples.



Using Goto to jump out of a loop would probably lead to the resources for the loop not being freed, resulting in memory leaks and other issues.


@Zethrax>>What "ressources" ? you mean n% and nn% ?


AdamStrange(Posted 2016) [#5]
simple answer:
don't use for/next, use while/wend or repeat/until with a trip variable so it can exit


grable(Posted 2016) [#6]
Using Goto to jump out of a loop would probably lead to the resources for the loop not being freed, resulting in memory leaks and other issues.
The same could be said for any exiting flow control, like Return or Exit too.
If some resources does leak, its fully a fault of the programmer for forgetting to Free them, which would happen with or without a Goto.

And im quite sure the blitz family of languages cleans up its stack scopes (if it even has them) when doing Goto.
Most if not all languages do, even C if it goes deep enough.


degac(Posted 2016) [#7]
Well, if you use nested For..Eachin (list) the flag/exit solution its still the best one.
I'm quite sure that Exit #Label works only in debug mode (never used so this could be just my wrong memory!)


Casaber(Posted 2016) [#8]
Bmax could definitly have use for a EXIT #, I've needed it several times already and just got tired to need patch every FOR NEXT into a ugly WHILE/REPEAT, same goes with using variables in FOR NEXT LOOPs. It seems like everything needs to become an WHILE/REPEAT in the end to get enough flexibility.

Using flag variables would add more logic and noise and not a good solution.

The GOTO HELL era was more about using GOTO as the *fundamental* construct* in program design, and ya that creates nothing but spaghetti code.
But to use GOTO in an orderly fashion within a block of code, that's perfectly okay. That's still structure.

(btw a EXIT label command is nothing but a GOTO, so i just look at GOTO as a missnamed "EXIT label")


Casaber(Posted 2016) [#9]
I must say, old instincts creates something disturbing with having to exit a for next loop using a GOTO..
as you never know what happens underneath the surface. The documentation should take care of to make the programmer confident that.. "it's okay".


grable(Posted 2016) [#10]
Seems i remembered wrong about #labels and For in BlitzMax :/ Now i want it!

I rarely use Goto in BlitzMax to be honest, as i code primarily in SuperStrict where its disallowed for some oddball reason.
I could just go Strict, but i still like being in SuperStrict nonetheless.

In C though, i use it all the time. Nothing beats it when you have multiple exit points that do virtually the same thing (usually error handling).
Im especially fond of Computed Gotos for manual jump tables, great for building state machines, lexers, virtual machines etc.


Yasha(Posted 2016) [#11]
Im especially fond of Computed Gotos for manual jump tables


Be sure to check your output assembly if you use this. GCC has a pessimization pass that sometimes runs to convert `goto *label` into the equivalent of a while/switch construct. I don't know why it does this, nor exactly what conditions trigger it, but the GCC developers seemed to think that having `goto *label` actually compile down to a `jmp *register` was a bad idea in certain circumstances.

Dont fuss about using Gotos. Anyone who says they are bad are simply parroting a paper from the 1968 in a time where people used ONLY gotos and line numbers for flow control.


I disagree heartily with this, for the very simple reason that adopting this attitude will usually end up with the code degenerating across the board. e.g. for the original problem in this thread, goto is not the simplest solution, return is. The programmer who objects to moving the loops into a separate function needs to get over their aversion to abstractions, not to find ways to avoid refactoring. A well-designed function doesn't have these nested-layers-of-control problems in the first place - it's short and flat and constructs flow out of single blocks, or by composing higher-level abstractions (i.e. map).

By taking the shortcut and using a goto here, you're ignoring a sign that the code was badly structured and too deeply nested in the first place. Goto is harmful for this reason alone. Use more functions. Never repeat a control structure if you can help it.


Matty(Posted 2016) [#12]
Alternatively you could turn it into a single for loop and calculate your x and y each iteration and jump out of just one loop with a flag/exit.


RemiD(Posted 2016) [#13]
I like to use goto label in some cases because it follows the way i think and it simplifies the code (imo).
If you understand how your code flows and how to debug it, then there is no reason to have mysterious errors when using goto label.
I really don't understand why goto label has such a bad reputation... (especially in small procedures functions = no "spaghetti code")

Anyway, thanks for your suggestions.

I like the alternative that Zethrax suggested, even if it is not simpler to use imo.


grable(Posted 2016) [#14]
Be sure to check your output assembly if you use this
I dit not know that, but i havent noticed it either to be honest. And i always check the assembly of critical code like that ;)

About Goto, well im glad i have the option of using it when i need to. I find the religious disdain for it laughable really.
If you consider it harmful and/or are unable to use it properly, then dont. But dont keep spreading FUD and in effect scaring people off it for no good reason.
Its a tool like any other, and requires its operator to use it properly.

Its becomes kinda like that monkey experiment ;)


Yasha(Posted 2016) [#15]
spreading FUD


The negative effect of working with goto is literally demonstrated in action in the thread above where you're advocating using goto as an escape-hatch to ignore poor structure instead of refactoring. Hardly dogma when it comes from empirical evidence that this usage directly harms code quality (in a way that can be objectively measured via code metrics, no less!).

I'mma revise my own recommendation back to "never use goto", since Dijkstra's lesson apparently still hasn't sunk in despite it being 48 years old and counting. The attitude expressed above is exactly the problem: if you start to "make exceptions" when you "know what you're doing", you write measurably poorer quality code than if you had the discipline to rewrite without it.


grable(Posted 2016) [#16]
Using code metrics is a pretty good straw man, since they add low scores for using goto on purpose!

So a double for loop is poor structure? Give me a break.

Good code:
#outer
While i < 10
  While j < 10
    j :+ 1
    If j = 5 Then Exit outer
  Wend
  i :+ 1
Wend
Bad code:
While i < 10
  While j < 10
    j :+ 1
    If j = 5 Then Goto done
  Wend
  i :+ 1
Wend
#done

Sorry, i see no difference between using Exit or Goto, they do the exact same thing. Even at the assmebly level. Its just one is more powerful than the other.

And no, im not making exceptions since i dont ascribe to the notion its harmful in the first place.
What im saying is know how to use it properly, apparently it has taken 48 years and people STILL dont know how ;)


Yasha(Posted 2016) [#17]
Nested loops are poor structure. Not cripplingly poor on their own, but all explicit control statements add complexity and potential confusion to code. So the problem with the example above is that you're trying to find a way to inline the loops into the surrounding body code, rather than factoring out the loop machinery. Goto is enabling you to do this and encouraging you not to excise explicit use of nested loops from your code, which would make it better by reducing the amount of explicit control machinery interleaved with your logic flow. Idealized code does not mix abstraction levels.

There is no difference between Goto and named-Exit in this scenario. The code is identical. There is no reason to use either of them because you should be moving the loop and loop-exit operation away from the operational code that makes up the loop body. If you need two loops, find a way to cleanly compose them into one operation first, then apply it to the operations it's supposed to control.

Again: the insistence that the above constitutes "proper use" is the entire problem. It obstructs the option to ditch nested control structures altogether and use a clean design for the program instead. The above is a pathological usage.


RemiD(Posted 2016) [#18]
A case which is more meaningful that the code that i have posted in post#1 is if i want to determine if one entity of a list occupiesthesameplace/intersects with another entity of another list, and if i find that yes, i can exit the double for next loop more quickly (with goto label or 2 exit + a state variable as Zethrax suggested)


@grable>>good examples, some fanatics will probably bug when they see that ;)


@Yasha>>I have no idea what you are talking about, all i know is that my code represents my thinking and works fast enough and has no bug... (i know that i am not at your level, but i can still code some good things you know, even if the form is not ideal)


grable(Posted 2016) [#19]
Then what would you consider a "clean" design? There is such a thing as over-engineering or over-abstractionism in this case.
Sometimes a loop is just that, a loop.

No need use fancy functional programing aspects like Map, Fold, Zip and the like.
Yes, they make some code look pretty nice, and for the most part, "when used properly ;)" they do their job with enough efficiency.

But all abstractions carry with them a cost, in either memory or cycles. And i care about my code enough to limit the amount and especially levels of abstractions. Because i find too much abstraction is even worse for readability than piling it all into one function (not that i do that very often mind)

Im a low-level guy and smell of assembly when coming home from work, so that may be the reason i dont ascribe to all these "x considered harmful" things.
Give me ANY primitive and i can probably find multiple ways to abuse them, but that doesnt mean we should get rid of them!

Right tool for the right job and all that :p


Guy Fawkes(Posted 2016) [#20]
I disagree. Coding is an art. Code the way YOU want to code! Do NOT listen to their programming standards bullshit! As long as it works, it's clean, fast, & efficient then do it the way YOU feel is best for YOU! Stop taking pointers from "the man" on syntax positioning & come up with your OWN style of coding! SCREW THE MAN! <3

~GF


Cocopino(Posted 2016) [#21]
@Yasha
Nested loops are poor structure.


Ok... What would be good structure/less confusing code when iterating through all tiles on a map without using a nested x and y loop for example?


Casaber(Posted 2016) [#22]
Computed GOTO's are not a good idea I think, and I've thought long and hard about that bc I used to love it too, CASE replaces that technique COMPLETELY and using a better approach IMO. CASE is a beituful thing when used right.


Casaber(Posted 2016) [#23]
Just on a related note..

I divide code golfing into two categories.. tricks that actually REVEALS meaning, and tricks that HIDES it.

I love the 1st kind. That's what code is all about.


grable(Posted 2016) [#24]
Yeah, switch/case does look better. But doesnt always perform great.

One can hide computed gotos pretty good using macros though. Enabling swapping it out for a switch/case or even an if/else chain without changing any of the code if need be. And with XMacros that pesky table goes away too ;)

For building VMs it cant be beat. Ive not seen GCC build a jump table out of my dispatch loops even once :(
And when that opcode list goes above 100+ its going start taking its toll on a switch/case.

Of course it cant beat a hand made VM in assembly, no compiler can. But making and debugging (the most important part) a pure assembly VM is painfull, and ive done my fair share of that so C it is hehe


Casaber(Posted 2016) [#25]
I'm not sure about how effecient CASE is nowadays, but I would not say they are bad hardware wise if done correctly.

That made me think of something, haha anyone want to see a NES emulator handcoded in 30min from scratch every line hardcoded (speeded up abit).



Most ppl shush about showing their code until their finished. You never see the actual WORK. All that sweat is the interesting stuff. Not the finished product.

Code style is such a personal thing, one should never do something just bc everyone else does it.
Find your own way that way you also might discover things others will not.


RemiD(Posted 2016) [#26]

Find your own way that way you also might discover things others will not.


like new ways to provoke errors/crashes/freezes ? ;) (just joking)


Casaber(Posted 2016) [#27]
That too, everything goes you know ;)

It's a package deal.


AdamStrange(Posted 2016) [#28]
@grable
And when that opcode list goes above 100+ its going start taking its toll on a switch/case.

Sometimes i smell of assembler too.
Here's a dirty solution for BIG list based if/case statements

1. we need to have one thing in place. we will be making decisions of a number based options. E.G. opcodes from 1 to 2000
2. we now use a binary if ladder this is for 0 or 1:

if opcode = 0
  do opcode0
else
  do opcode1
end if


now if there were 4 opcodes we extend the ladder by ONE if:
if opcode < 2
  if opcode = 0
    do opcode0
  else
    do opcode1
  end if
else
  if opcode = 2
    do opcode2
  else
    do opcode3
  end if
end if

finally lets do 8 opcodes with 3 IF commands
if opcode < 4
  if opcode < 2
    if opcode = 0
      do opcode0
    else
      do opcode1
    end if
  else
    if opcode = 2
      do opcode2
    else
      do opcode3
    end if
  end if
else
  if opcode < 6
    if opcode = 4
      do opcode4
    else
      do opcode5
    end if
  else
    if opcode = 6
      do opcode6
    else
      do opcode7
    end if
  end if
end if


it's dirty to look at but very efficient ;)


Casaber(Posted 2016) [#29]
When you code together in a big group it's important to speak the same style and not just the same language,
or to have the time to convert back and forth your private style and an outward/common style.

But when you code and need to connect yourself to solve something, you should just do whatever feels best for *you*,
and the rest of the world may aswell go to hell with their opionions. (Opionions which they have for the same reasons on their behalf).

That's important stuff. That's religous, in that you do something you feel good with in life. Not to be toyed with. That would just be respectless and tactless.


Casaber(Posted 2016) [#30]
Those IF ELSE would make any processor puke cycles. I can't remember how SWITCH CASE are implemented.

Tables, Indirect jumps, but those are nonos with modern processors. But It would be far better than lots of sequential branches.
Somehow it minimise branches, you don't want branches. A good implemented SWITCH is powerful. I need to check how Bmax implements it later on.

But the outside is equally important, LOVE how it eliminates the noise of deep ELSIF clauses sometimes.

Select True
Case something = 5
Case something > 10 And something =< 20
Case something >1000
.. 10 miles more of this would be no problem.. not for the programmer, not for the processor
Default
End Select


grable(Posted 2016) [#31]
@AdamStrange
Yeah, binary search does help somewhat. But its a bitch to code up manually ;)
Id much rather generate something like that, and when one is generating stuff one might as well generate the fastest code even if it looks horrible :p

I would expect a static binary search to be faster than a dynamic one.
But depending on the usage, the tests ive seen show that anyting less than 256 items and a linear search beats it (on relatively modern hardware).

@Casaber
BlitzMax is especially bad at Select/Case, it gets converted to an If/ElseIf chain at the assembly level.


Casaber(Posted 2016) [#32]
Is Bmax that cheesy in how it compiles? That's the output of a cheesy translator.

EDIT
Started reading how other does it, MS's compiler seem to be doing a good job.

https://news.ycombinator.com/item?id=1301529

http://www.codeproject.com/Articles/100473/Something-You-May-Not-Know-About-the-Switch-Statem
http://encosia.com/first-class-functions-as-an-alternative-to-javascripts-switch-statement/
http://embeddedgurus.com/stack-overflow/2010/04/efficient-c-tip-12-be-wary-of-switch-statements/
http://stackoverflow.com/questions/14067547/how-switch-case-statement-implemented-or-works-internally
https://sourcemaking.com/refactoring/replace-conditional-with-polymorphism
http://archive.oreilly.com/pub/a/server-administration/excerpts/even-faster-websites/writing-efficient-javascript.html
http://www.embedded.com/design/programming-languages-and-tools/4397803/Interrupts-short-and-simple--Part-1---Good-programming-practices
http://code.activestate.com/recipes/410692-readable-switch-construction-without-lambdas-or-di/
http://www.dreamincode.net/forums/topic/172744-stack-implementation-using-arraydo-while-and-switch-case/


AdamStrange(Posted 2016) [#33]
Those IF ELSE would make any processor puke cycles


You have to really look at what is happening in there:
In the above example for any of the 8 opcodes, there are only EVER 3 IF commands

it scales by a factor of 2

so for 16 opcodes, you would have 4 IF's
32 opcodes 5 IF's
..
256 opcodes would be 8 IF's

the more you have the more efficient it becomes

It looks awful, but the logic translates directly into assembler nicely


Casaber(Posted 2016) [#34]
Ya It will be no problem whatsoever to translate that into assembler, it is 1:1. You could basically do it using search & replace.
But to branch is not cheap you want to minimize jumps.

EDIT
Extreme tricks aside.. I guess it's down to 1 Indirect jump versus a few say 2-8 serialized branches,
I wonder which one messes up cache and prediction mostly. I couldn't say without testing as processors change so rapidly. It could be that the naive solution wins. If so then Bmax CASE will do great.


Casaber(Posted 2016) [#35]
Control instructions are interesting, If that's bad then everything goes bad.

To exit double loops I guess you could use trick like setting the variables aswell, but that would not be an imm exit. I guess interesting in some cases. Less flags and you reuse the "if inside NEXT".

for temp = 1 to 25
for temp2 =1 to 10

temp2=10 ; temp = temp = 25 ' make both happy, exit but finish the code from here

next ' exit when reached here
next ' exit when reached here


Cocopino(Posted 2016) [#36]
I don't really get the problem here...
Code like that never just occurs "in the wild" in your program. If you've created a nested loop you'll need to break out of, it will basically always mean you were looking for something and found it, right?

Function ValueExists:Int(value:Int)
	
	For Local x:Int = 0 To mapWidth - 1
		For Local y:Int = 0 To mapHeigth - 1
			If map[x, y] = value Return 1
		Next
	Next
	Return 0

End Function


I don't see how this can be optimized or cleared up any further?


Yasha(Posted 2016) [#37]
@Cocopino Rather late in the conversation, but since you asked...

What would be good structure/less confusing code when iterating through all tiles on a map without using a nested x and y loop for example?


Map/Foreach:
for_each(tiles, do_work_on_tile)

...where `tiles` if your set of tiles in the game-map, and `do_work_on_tile` is your loop body. NB that in most languages you can inline the do_work function as a lambda, which makes this a lot clearer to look at; however, if you've really separated your concerns, even this call will be "away" from the per-tile work because the best code operating on collections will try to avoid thinking about the existence of other elements in the collection, so the definition of "what to do to one tile" shouldn't need to be written out anywhere near the code that asks it to be applied to all of them.

With a good modern compiler, there is zero overhead to this approach. Even with BlitzMax, there is very little, because modern processors are rather good at calling functions. Either way, it doesn't matter much because you can always convert to a clunkier design after you have evidence that the cleaner design is too slow; but 99% of the time performance doesn't matter anywhere near as much as readability.

You can't write code like this in Blitz3D because of the lack of any kind of support for first-class functions or callable objects, but you can a) factor out the loop from the surrounding code, b) factor out the loop body to its own function, and c) redesign the data structures to only require one tier of control (e.g. is there anything intrinsic to the tiles requiring a two-level loop, or are you just letting presentation dictate how you manage the collection? Normally a single loop would make more sense, even for something to eventually be displayed in 2D space).

you don't want branches


What you want to avoid are inconsistent branches. A branch or indirect jump that goes the same way each time is almost free. Code with more branch instructions can be faster than code with just one point of dispatch if it means that the prediction for the single point of dispatch is always going to be wrong due to having a different target each time.

The thing with using computed gotos for a VM above, for instance, gives each virtual instruction its own jump point - and in so doing improves the prediction failure rate from >99% to somewhere in the region of 50% (IIRC), with dramatic consequences for the VM's performance because suddenly it's magically getting hardware prediction for virtual instructions. Similarly with the nested vs. linear if-chain: a processor could get moderately good performance out of a short, linear chain simply by predicting "no" for every branch, for instance, and the chance of failure is still only 1/Length, whereas the chance of failure in a binary search is ~50% for each branch unless your data is very unevenly distributed.

Every processor is different, but we're well past the era when all jumps were bad news.


Cocopino(Posted 2016) [#38]
@Yasha
With a good modern compiler, there is zero overhead to this approach. Even with BlitzMax, there is very little, because modern processors are rather good at calling functions


I have no compiler knowledge so correct me if I'm wrong, but to be able to use "for_each(tiles, do_work_on_tile)", doesn't that mean:
1. we still need a container/list to store the tiles
2. we still need to store the grid location somewhere - the tiles now need to be objects/types?
3. the amount of iterations needed will stay the same

I fail to see how this approach would be less overhead...?


Yasha(Posted 2016) [#39]
It wouldn't be less - by "zero" I mean "zero in addition to". i.e. not actively losing anything.

I'd assume the tiles are already objects of some sort? But you can generalize this to cover anything. You can have versions of `map` that accept lazy/implicit/range-type values so that they don't actually need e.g. an array of the numbers from 1 to 1000. Depends what you'd want it to do.


steve_ancell(Posted 2016) [#40]
grable:
Im afraid not. Using a label and goto is the only way for Blitz3D and BlitzPlus.

I beg to differ, I use a flag variable just like Zethrax.


grable(Posted 2016) [#41]
@steve_ancell
He was asking about an equivalent to Exit, which the Goto is the only option.

I assumed he didnt want to use an exit flag, which is why i worded it like that.
Besides im sure the concept of an exit flag is quite obvious to anyone who has coded for more than 5 minutes ;)

Personally i dont like exit flags, it adds clutter to the algorithm and it adds an additional compare which will slow down tight loops.


RemiD(Posted 2016) [#42]
@grable>>i didn't know about the exit flag, that's why i used goto label... :P


Casaber(Posted 2016) [#43]
Yasha Ya but it's not very viable for a human to know the periods of branches. You can use the aspects how often branches are taken and place them using some priority I guess and make it easier for the cache. But all those are things that you want a compiler to do ,or it just wonīt be done. Those details are not humane. Branches are evil.

EDIT I guess I just donīt trust caches / prediction very much, they have some clever pattern reconition, but Iīve seen too much slowdowns (2012-2015 era of processors) to believe in them completetely.


But I know that the #1 what makes a expansive computer faster is just that; improved predictions and caches.

For example my i3 3Ghz is no match for my i5 1.9Ghz. I guess that proves that they do something. But not everyone has amazing machines.
The actual difference I measured for that was (same graphics performance and DDR3 etc), but logic and conditionals perform 20-40% better (1.9Ghz) than the 3Ghz.

EDIT
I've never learned how virtualsing processors affects predictions and caches but I reliase they must play an important role in this game of prediction and caching. They would play a good part, as dividing up everything would make everything more.. I mean at least ONE processor would always have the correct precditcion in what it is executing. So that would make sense to me.

But still.. bottomlines becomes; The more branching that happens inside code the more you need a high end machine, the Ghz does not mean anything. How branches is handled is everything.


Casaber(Posted 2016) [#44]
Which brings us to conditional executable instructions and how lovely they are.
ARM survives on them. X86/X64 has them but they are not very much used as the ARM ones I feel.

I wonder if that's why MIN and MAX is so fast in Bmax. I donīt know.


Casaber(Posted 2016) [#45]
LUA had no Continue and got a GOTO in return of that request.
http://stackoverflow.com/questions/3524970/why-does-lua-have-no-continue-statement

I guess GOTO replaces both EXIT # and CONT #.

Would anyone be so kind and unlock GOTO in SUPERSTRICT? Color it red if you want but allow it and it would be wonderful. Shh I know this GOTO guy, he's a good one. Let him in.


RemiD(Posted 2016) [#46]

Color it red if you want


Color it flashing glowing red with exclamation marks around it to really remind goto label is bad, really bad. ;)