Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : EXIT from multi-line IF/THEN....
Author | Message | ||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9072 |
Hi there. I am just trying to clean up my code that at the moment uses GOTO out of loops. DO and FOR are taken care of with EXIT DO and EXIT FOR respectively, but there is no EXIT IF command, so I am "Making one" via a flag and ENDIF. In other words, IF Y THEN ENDIF kind of idea. Is this acceptable? What I DON'T want to do in my attempt to clean up all my loops, is introduce ANOTHER bad practise in the process! A code sample:(not wanting anyone to re-write this, it is only for context of the ENDIF idea) The yellow highlighter bar in this GIF image, shows the line I have concern with. Prior to this week, all my loops had 'Dirty' exits, by GOTO'ing out of the loop, which is a bit naughty, so I am cleaning up all the code now so that ALL loops have a clean exit, and one single ON x GOTO concept at the bottom, and I just use flags('Y' in this case) to signal that exits need to happen at a given point. This all seems to be working fine. FOR/NEXT is easy to deal with via EXIT FOR. DO/LOOP is easy to deal with via EXIT DO Multi-line IF/THEN exits are a little different. So, looking at how I have written my exit using a flag and an ENDIF - is this acceptable, or is there another(better!) way? I have quite a few of these multi-line IF/THEN's to change, so I only want to do it once. Smoke makes things work. When the smoke gets out, it stops! |
||||
Bizzie Senior Member Joined: 06/07/2014 Location: AustraliaPosts: 185 |
The select case statement with a break would do your job. I personally have not seen this in any flavors of Basic. It is however available in many other languages. Look for the switch command in C, Java or PHP for examples to name a few. Rob White |
||||
CaptainBoing Guru Joined: 07/09/2016 Location: United KingdomPosts: 1986 |
FWIK there is no EXIT IF in MS basics (which MMBasic leans on heavily). Certainly wasn't when I stopped writing professionally (then at VB6) and I can't remember anything like it in QB, etc (Basica and GW Basic still used line numbers and so don't properly support structured code). I know it is considered bad practice and I try to write IF sections that only include a positive test so i can nest them nicely, but even then on some nasty stuff I will still use a label right before a relevant END IF and GOTO it. Even bailing deep out of a nest of IFs will work just fine and it is faster than END IF, END IF, END IF, END IF, END IF etc... What's the point of jumping to another jump instruction? Remember: the END IF is just a local point to which a jump will be executed if the condition evaluates false (assuming no ELSE). A good example would be to look at compiled code and as most processors are fairly simple beasts, all they have is JUMP or BRANCH so that is what they use to zip round bits of code that are not required after a test. The use of a GOTO is a good analogue to this and it is fast. Here is an example of an IF/END IF in compiled code - note the jump to a temporary label (I have removed sections of ASM that are not relevant ;if nn=fl then movf FL,W subwf NN,W btfss STATUS, Z goto ENDIF16 ;print "." [...] ;end if ENDIF16 [...] If you are not familiar with PIC assembler, the btfss skips the next command if the specified bit is set (in this case the zero bit). The test of the condition results in a GOTO on false - exactly what you are doing (but feeling bad about ) The one flow control that is missing (if we are to adhere to the MS standard) that I have used is EXIT SELECT (at least it isn't in 5.3). This gets the same 'label-before-END' treatment from me if I can't make the code tight easily. That said, I do find that most tests can be structured tightly by re-evaluating what I am trying to do and perhaps approaching from a different angle. I have always said that GOTO has a place - just only use them if there is (apparently) no other way. Make the label meaningful and it maintains the look of the flow. So long as the code is nice to read and fast, why beat yourself up? INCOMING!!!! |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3675 |
Grogster I'm fairly sure it won't work, because ENDIF is lexically matched with its IF. You'd want the equivalent of EXIT IF (which I think doesn't exist). I'm not sure in your code where you'd want it to go. If it's where I think then you could use EXIT DO instead, I think. Or, it looks like you could change the line concerned and the ENDIF above into ELSE (and the ENDIF further down). In C I'd probably follow the already mentioned way using a switch (select case or whatever in some languages). John |
||||
Geoffg Guru Joined: 06/06/2011 Location: AustraliaPosts: 3165 |
In MMBasic ENDIF does not actually do anything when it is executed. It only exists as a marker so that the interpreter can scan forward to find the end of the IF statement. This is used when the IF test is false, in that case the interpreter will scan forward looking for the matching ENDIF and resume execution after it. Putting the ENDIF at the end of an IF will just confuse the interpreter because it cannot evaluate the IF while scanning. The bottom line is... DON'T DO IT Geoff Geoff Graham - http://geoffg.net |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3675 |
By which I mean that any time you find an ENDIF there should be one and only one IF matching it (inevitably earlier in the code), with any other similar lexical items (FOR/DO loops, further IF/ENDIFs etc) properly nested within them. (And if there's an ELSE it'll be between them and so on.) This sort of thing became known in some languages as "..." - meaning obvious or some such! When there's a formal grammar for a language you can work through it and it should always work out this way. (In essence this is what a compiler has to do.) John |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9072 |
OK, so I won't mod anymore IF/THEN's like this. Having said that then, how do you exit from a multi-line IF/THEN cleanly, WITHOUT an EXIT IF command? It may well be do-able with MMBASIC as-is, but I will need a little prod as to how this is done if that is the case. Using my example above, what I am trying to do with the highlighted line, is exit totally out of that IF/THEN, down to line 803(technically then to 805). IE: At line 784, what I need is something that can do the same as IF Y THEN EXIT IF, resulting in the code dropping down to line 803 in this example and continuing from there(and then dropping out to line 805). Based on what has been written above, and if ENDIF is simply a marker for the interpreter and does not "Do" anything in terms of code processing exactly, can I just use EXIT DO as JohnS suggests? This will drop me right out of the IF/THEN and it's hosting loop. If that works, that is fine with me - so long as that is still considered a clean exit, yes? EDIT: In other words, can I use IF Y THEN EXIT DO at line 784, to effectively drop me back out to line 805? Smoke makes things work. When the smoke gets out, it stops! |
||||
erbp Senior Member Joined: 03/05/2016 Location: AustraliaPosts: 186 |
You could try changing line 784 to "If Y = 0 Then" and add a new line after the current 801 containing "End If" - this would be the matching End to the If on 784. I find thinking about If conditions in positive logic terms works best - i.e. what condition do I need the specify so that the following Then block of code gets executed rather than skipped. |
||||
disco4now Guru Joined: 18/12/2014 Location: AustraliaPosts: 844 |
The construction below is useful if you want to test for multiple things IF blah THEN . . ELSE IF blah2 THEN . . ELSE IF blah3 THEN ... ELSE ... (none of above) ENDIF I think the ELSE statement to replace the two highlighted lines might get you close. Regards Gerry Latest F4 Latest H7 |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9072 |
Hey, I think you are on to something there, Gerry! Made the change you suggested(replaced those lines with an ELSE), and the code works exactly as expected. This seems like the way forward, yes? Smoke makes things work. When the smoke gets out, it stops! |
||||
disco4now Guru Joined: 18/12/2014 Location: AustraliaPosts: 844 |
Yes,the way forward in my experience. You can make the IF statements easy to read if you selected the right method. This sytle works well if you only want to do one of a number of things. The first one that is true is done, the rest are skipped. IF blah THEN . . ELSE IF blah2 THEN . . ELSE IF blah3 THEN ... ELSE ... (none of above) ENDIF Use this if you want to possibly run each one if it is true. IF blah THEN . . ENDIF IF blah3 THEN ... ENDIF It all about making it easy to read 1 year down the track. A suggestion to make it easier to read is create a subroutine for the DEBUG printing like below. SUB DPRINT (m$ as STRING) IF DEBUG THEN PRINT m$ END SUB In your main code just call it like this DPRINT("Exit Button Touched. (database editor/new)") The advantages are your code is easier to read. (A lot of IFs are gone and the ones left are easier to visualise.) Also if you want to tweak how you write errors etc then you do it all in one place, the DPRINT SUB. You just start to use DPRINT like its another command after a while. You could do and SPRINT SUB for the SYSLOG stuff. Regards Gerry Latest F4 Latest H7 |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9072 |
Debug Sub is a nice idea - I will make that change also. As you say - less IF's to visualize. The WRITE_SYSLOG sub is called if the SYSLOG flag is set. This flag(among many others) is set via checkboxes in the settings menu. I could have the WRITE_SYSLOG sub check the flag though, then it is not another IF in the mix of the main guff..... Right, I will set about changing all these lumps of code so that all the exit paths for the code are neater and more in line with how it should be. I do like the ON x GOTO.... command, as this allows me to use one flag to decide where to go, and when the code gets out the very bottom of the routines and loops, this one command then does any and all GOTO branching for me, with no nasty jumping out of loops. Smoke makes things work. When the smoke gets out, it stops! |
||||
lizby Guru Joined: 17/05/2016 Location: United StatesPosts: 3022 |
I really like the SUB DPRINT idea. You can then test for different debug conditions. [code] SUB DPRINT(A as string) IF Debug1 or Debug2 or Debug3 then PRINT A END SUB [/code] ... On further consideration, I don't know what I meant by the above multiple Debug#s. But I do like the SUB DPRINT idea. PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9072 |
Smoke makes things work. When the smoke gets out, it stops! |
||||
MicroBlocks Guru Joined: 12/05/2012 Location: ThailandPosts: 2209 |
One problem with a debug subroutine is that it takes time. Time that when using time sensitive tasks will influence the working of your program depended on if the debug flag is set or not. It can (will) cause that a program works perfectly while debug is on and not work or not work sometimes when debug is off. Ask me how i know. :) :( Just something to be aware of, as it can be very difficult to find. Microblocks. Build with logic. |
||||
isochronic Guru Joined: 21/01/2012 Location: AustraliaPosts: 689 |
Good advice there. Once (in assembler, but the logic still holds) I was debugging a program that was at the maximum number of subroutine return addresses in a hardware stack..adding another call (debug or print) gave apparently random execution or crashes, exasperating and at the worst time |
||||
isochronic Guru Joined: 21/01/2012 Location: AustraliaPosts: 689 |
BTW wrt the nested if/do etc, [there are no doubt several ways and opinions] I think a WHILE construct with a compound test condition would be clean ? |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9072 |
Yes, good advice from MB there - all knowledge is power. I have not had a chance to work on this anymore just yet - other things in the way. I hope to get back to this tonight. Smoke makes things work. When the smoke gets out, it stops! |
||||
Print this page |