General question about "continue" vs "nested ifs"

Community Forums/General Help/General question about "continue" vs "nested ifs"

Matty(Posted 2013) [#1]
Hi all,

This is a general question, I'm not looking at optimisation issues just some general thoughts on the difference between the two approaches.

I have a lot of code in a database package I work with that often can be written either as

loop here:
	if some statement = true
		continue
	endif

	if another statement = true
		continue
	endif
	
	do processing
end loop


alternatively
loop here:
	if some statement = true
	else
		if another statement = true
		else
			do processing
		endif
	endif

end loop



Usually the programs are pretty simple, the logic is pretty clear and easy to understand, but I'm not sure what the advantage is of doing it one way over the other in this instance.

I can see for a more complex case it is useful to use one over the other but for something as simple as this - what differences does it make internally? Is it just a stylistic choice - aesthetic only?

EDIT - I know I can make this more complex again by putting the whole if statement on one line in some cases - but not all simply because of the way the programs work...


xlsior(Posted 2013) [#2]
There's also ElseIf:

While Not whatever
	If a=True Then
		Print "A is true"
	ElseIf b=True Then 
		Print "whatever"
	Else 
		Print "none of the above"
	EndIf
Wend



Kryzon(Posted 2013) [#3]
Are you using a Blitz product? what language are you in?

If it's another language, try some hocus-pockery such as this...
Switch(True) {
	Case (boolean expression 1):
	Case (boolean expression 2):
	Case (boolean expression 3):
	[...]
	Case (boolean expression n):
		Continue;
		Break;
}
Then all expressions give the same 'continue' result, but you're still individually checking each.

@Yasha: Oh, I see what you mean. I'll leave it there so we can have a laugh at it.


Yasha(Posted 2013) [#4]
Is it just a stylistic choice - aesthetic only?


Pretty much.

Go with the one that makes it most visually obvious what's happening. For shortish blocks, that's probably the second one (at least... rewritten to test against "false"): if in one glance you can see that "do processing" is safely protected inside an if block, you know how the conditions will affect its execution.

If on the other hand "do processing" is quite a long and possibly deeply-nested bit of code that doesn't cleanly fit on the screen or whatever you can take in in one glance, and you have several guard conditions you want to check all in a row, perhaps it's better to separate the action from the checks and think about them separately. It might make the code more readable if a single large block is not indented for little good reason, especially if there's no alternate path. (On the other hand, often if you have a block that breaks the visual flow in this way, it's a sign you should consider factoring some of it out and make the loop body smaller.)

The correct one is the one which makes it less likely that you'll make a mistake when you see the code in context. For some code one will be clearer than the other, but they do the same thing.


@Kryzon: most of the languages that call it "switch" don't allow you to put expressions on the cases, only constants. They want you to use "if" for that.


Kryzon(Posted 2013) [#5]
If you're in blitz, there's no need for the EndIf (only required for IFs with more than one line).

You can then write:
	If some statement Then Continue
	If another statement Then Continue
	If another another statement Then Continue
	If another another another statement Then Continue
	
	;Do processing.
Single line IFs, completely unrelated to each other.


Matty(Posted 2013) [#6]
Thanks Yasha..I was mainly interested just in the thoughts behind the two stylistic approaches which you've answered nicely...Kryzon - language was not important here just the methodology so it was pseudocode...


Derron(Posted 2013) [#7]
If the "variable" you are checking is received using a function/method-call, it will be better to use the switch/select-approach as the variable is only set once in the header of that block. If you use the "if"-approach you will then most likely have to cache the output using a local variable.
if myobject.GetType() = "circle" then XY;continue
if myobject.GetType() = "rectangle" then XY;continue
if myobject.GetType() = "triangle" then XY;continue

-> in the case of triangle the GetType() thing would be called 3 times.

Select myobject.GetType()
  case "circle"  XY;break
  case "rectangle"  XY;break
  case "triangle"  XY;break
EndSelect
-> GetType() is only evaluated once (but also checked 3 times in the case of "triangle").


So the Select-approach saves the caching in a local variable in the case of a functioncall which has to get compared.


To add something to Kryzon's post:
As soon as only "one" thing is compared to a may-be-growing-variety a Switch/Select-approach is most likely the better option (imagine EVENT-Type-Checks or other code using different CONST-values to distinguish things).

It is also shorter to use the Switch/Select-blocks when doing things like:
If myobject.GetType() = "triangle" or myobject.GetType() = "rectangle" or myobject.GetType() = "octagon"  or myobject.GetType() = "spiral"
  print "not a circle"
else
  print "no triangle, rectangle, octagon or spiral"
endif

Select myobject.GetType()
  case "triangle", "rectangle", "octagon", "spiral"
     print "not a circle";break
  default
     print "no triangle, rectangle, octagon, spiral"
End Select


Readability is improved the longer variablenames or object-chaining gets (as soon as the 80chars per line is reached one should linebreak and this makes the formatting even more work).


I know Matty asked about the "methodology" but the readability is also depending on the structure your code uses.


bye
Ron.


GfK(Posted 2013) [#8]
If you're in blitz, there's no need for the EndIf (only required for IFs with more than one line).

You can then write:
If some statement Then Continue
If another statement Then Continue
If another another statement Then Continue
If another another another statement Then Continue

;Do processing.
Single line IFs, completely unrelated to each other.

There's no need for "Then" either.
If some statement Continue
But I find every shortcut taken makes your code less readable. I generally prefer Select/Case as it makes for more readable code.

One neat little 'feature' of Select/Case is the ability to do this (which is really just expanding on what Kryzon said):
Select True
  Case X >= 0 And X <= 5
    'do something
  Case X >= 6 And X <= 10
    'do something else
End Select

As far as I know, you can do that in any BRL product (don't know about Monkey), and since this is the Blitz site, it's definitely worth a mention.


RemiD(Posted 2013) [#9]
Several If Endif do not produce the same result than If Elseif Else Endif.

See :



GfK(Posted 2013) [#10]
Several If Endif do not produce the same result than If Elseif Else Endif.
It's not meant to (is that what you were saying?)

In a bunch of If/EndIfs, every one gets processed, whereas using If/ElseIf/EndIf, only the first one that returns True gets processed - the rest are skipped.


TomToad(Posted 2013) [#11]
loop here:
	if some statement = true
		continue
	endif

	if another statement = true
		continue
	endif
	
	do processing
end loop


I would do this as

loop here:
     If not some statement and not another statement
          do processing
     Endif
end loop


Edit: Had it right the first time.


RemiD(Posted 2013) [#12]

It's not meant to (is that what you were saying?)


Gfk>>Yes.

This :
if some statement = true
 ;continue
endif
if another statement = true
 ;continue
endif


Will not produce the same results as this :
if some statement = true
 ;
else
 if another statement = true
  ; 
 else
  ;do processing
 endif
endif


"some statement" may be true and "another statement" may be true, and with the first code, the code concerning the "another statement" will be processed.


Yasha(Posted 2013) [#13]
@RemiD: actually they will do exactly the same thing.

The whole point of the OP was to ask about the Continue command. Since Continue will jump back to the start of the loop, if the first condition is true the second will never be tested no matter whether it's in an Else block or not, because the presence of Continue is manually re-creating the functionality of the Else branch.

(Note: Continue does not exist in B3D, so if you're not familiar with BlitzMax or C, this code may not do what you think it does!)


RemiD(Posted 2013) [#14]

The whole point of the OP was to ask about the Continue command. Since Continue will jump back to the start of the loop, if the first condition is true the second will never be tested no matter whether it's in an Else block or not, because the presence of Continue is manually re-creating the functionality of the Else branch.

(Note: Continue does not exist in B3D, so if you're not familiar with BlitzMax or C, this code may not do what you think it does!)


Ok, that is why, i thought continue was a way to say continue to do this and that.
Sorry, forget about what i have explained.