Strange if then else behavior

Started by michaelgreer, March 08, 2023, 09:00:05 AM

Previous topic - Next topic


This is an abstraction of a code issue we are seeing:
0005 let mike$="P"
0010 if mike$="P" then {
0015 print "Yes P"
0020  } else if mike$="T" then {
0025 print "Doing T too"
0030  }
If you execute this, you get both outputs when it seems you should not get the "Doing T too".  I realize this is not great coding (I didn't write it) but it seems it should work.

James Zukowski

Yes, it looks like it should. If you add a brace before the second IF and close it at 35, it works fine. Evidently, if you {group statements} for the THEN, it's expected for the ELSE as well.
James Zukowski
Sr. Developer - J&E

Brand Industrial Services

Mike King

The issue is a result of the line oriented nature of the language.  IF ... THEN ... ELSE ... will basically process what is on the line.

To span multiple lines then the THEN or the ELSE *MUST* be immediately followed by the OPEN bracket otherwise the conditional processing ends.

What was happening is that when the system saw your ELSE IF MIKE$=... because the ELSE was not followed by a curly bracket the IF directive was now fully complete thus the next line was executed.

Personally I try to avoid curly brackets as they make lines hard to read.  I would enable formatted output in *IT and code the line as:

0005  mike$="P"
0010  IF mike$="P" \
        THEN PRINT "Yes P" \
        ELSE IF mike$="T" \
              THEN PRINT "Doing T too"
0020 !

Its just easier to read.

And where there are more than three lines in any of the of the IF blocks I usually put the code into a GOSUB with a label to make the code more readable.  For example in instead of just PRINT "Yes P" you had 10 lines of code to execute I'd put that in a GOSUB called something like Mike_Code_P.  (My $0.02)

Mike King
President - BBSysco Consulting

Mike King

Quick follow up:

To give you an idea of how my coding style looks have a look at *plus/inomads/inomads around the label Set_Userid:

If you load this program and do a standard LIST EDIT SET_USERID (or call the program up in the *it or *ed+ editors with Formatted output enabled) you will get something like this:

  IF NOT(%inomads'ForceLogon) AND %inomads'LogonReqd$<>"Y" \
   THEN %inomads'Userid$=NID;
  DEF UID="*Void*" LOCAL
  CALL "*secure","F:LOGIN"
  DEF UID="*"
  IF %inomads'Userid$="" \
   THEN objsec=NEW("*secure");
        IF objsec'unsecured \
         THEN MSGBOX "System security is not enabled but required for this transaction","Error","STOP";
              EXITTO SKIP_TX \
  IF %inomads'use_signon_uid \
   THEN GOSUB Linux_signon WITH reqd_uid$=%inomads'Userid$

Which I find fairly easy to read and follow. 

Now some of the lines if you list them un-formatted are quite long, with edited listing enabled the built in code formatting makes following the logic quite easy -- and in my opinion much easier than coding a bunch of brackets. 
Mike King
President - BBSysco Consulting

Mike Hatfield

Hi Mike, I had no idea you could do a LIST EDIT..... from the console prompt. very handy I think.
So, I thought I'd try it on the inomads program. The IT editor is set to 'editted list' and 'disallow lines'

I get this

0071 Set_userid:
Am I missing a setting somewhere?
Mike H

Mike King

Add a comma after the label to start the list from there.  Without a trailing comma you will only get one line.
Mike King
President - BBSysco Consulting

Mike Hatfield

Ok, got it.
Is this what I should see? The listing includes the internal generated line numbers so that you can edit at the command prompt ?
-}list edit set_userid,
0071 Set_userid:
0072       IF NOT(%inomads'ForceLogon) AND %inomads'LogonReqd$<>"Y
:           THEN LET %inomads'Userid$=NID;
:                RETURN
0075 !
0076       DEF UID="*Void*" LOCAL
0077       CALL "*secure","F:LOGIN"
0078       DEF UID="*"
0079 !
0080       IF %inomads'Userid$=""
0082 !
0083       IF %inomads'use_signon_uid
:           THEN GOSUB Linux_signon WITH reqd_uid$=%inomads'Userid
0085 !
0086       RETURN
0087 !
0088 start_trace:
0089       LET x$=PTH("*plus/inomads/tracefiles",ERR=*RETURN)
0090 !
Press <ENTER> to continue or <F4> to exit:

Mike H

Thomas Bock


You wrote
QuoteThe issue is a result of the line oriented nature of the language.  IF ... THEN ... ELSE ... will basically process what is on the line.

This rises the question how does PxPlus find the closing curly braket? Are there any performance aspects?
As I don't like premature RETURNs or EXITs my coding style looks like this.
if condition {
txt$  = "Are "
txt$ += "these "
txt$ += "lines "
txt$ += "processed "
txt$ += "in "
txt$ += "some "
txt$ += "way "
txt$ += "during "
txt$ += "execution "
txt$ += "in "
txt$ += "order "
txt$ += "to "
txt$ += "find "
txt$ += "the "
txt$ += "closing "
txt$ += "curly "
txt$ += "bracket?"
print txt$

Would that routine be faster using a premature RETURN?

Mike King


Yes the line numbers are assigned so you can edit at command mode if needed when running in text mode.  Mind you with PxPlus 2023 due in May you should be able to run EZWeb on a Linux/MacOS/AIX box then use ED+ to edit your programs graphically from any browser.


When looking for the closing bracket the system has to scan ahead through the code, this is due to the interpretative nature of the language and that you can alter code at run time.  Given this, from a performance perspective it is better to keep the directives on one line as scanning will be faster. 

Also, as mentioned earlier, I generally prefer moving multiple lines to smaller subroutines.  A GOSUB takes very little time and will often run faster than scanning looking for brackets.  I also find it has the advantage that if I need to insert additional lines into an IF condition having them in a subroutine makes that easier especially when they are sub-ordinate IF directives. I find it also helpful if the subroutine name provides a 'clue' as to what the logic is doing.

For Example:

    IF QtyOnHand <= 0
      GOSUB BackOrder
      GOSUB CommitInventory

I have seen far too many programs not work because someone inserted or changed a few lines of code in between curly brackets that they didn't realize were present.  By avoiding curly brackets and using *IT or ED+ to format your code I find it makes it more readable and supportable.  I almost never use curly brackets (but maybe I'm just a bit weird in that respect).
Mike King
President - BBSysco Consulting


Thanks Mike.  Your comments on the Curly braces and forward scanning are very helpful.  I've found the UltraEdit text editor really helps when set for Pvx code to match braces.  Now I know to also reduce lines.   I use the GOSUB method often for simplifying the decision logic which can reduce lines processed by listing IF decisions lines in declining frequency and putting a return at the end of each.

Stéphane Devouard

After using IF {} ELSE {} for several years
I found it hard to follow especially when having several nested IFs
I started adding remarks to denote the level of nesting such as :

if some_condition { ! <-
if nested_condition { ! <--
if yet_another_condition { <---
... some code ...
} ! --->
} ! -->
} ! ->

But it is still hard to follow

I started coding in other languages (C#, PHP, JS) with fancy IDEs that have indentation
But even witht all the bells and whistles, a complicated algorithm is hard to follow
And I have watched numerous coding tutorials where it is recommended to avoid complicated nested if/else structures and use guards instead
Do all the tests that prevent the main logic to be processed, and return from the routine/method/functions
Then do the processing
Using Mike's GOSUB technique, that would be :

GOSUB Do_Some_Logic
if some_condition then return
if some_other_condition then return
if yet_another_condition then return
! // now do the logic

I also use the simple FOR/NEXT structure A LOT :

for (1)

if some_condition then break
if some_other_condition then break
if yet_another_condition then break
! // now do the logic

Stéphane Devouard
Portfolio | Work