Lazarus

Free Pascal => General => Topic started by: Munair on September 12, 2019, 01:04:06 pm

Title: Syntax curiosity
Post by: Munair on September 12, 2019, 01:04:06 pm
I actually miss a general discussion section on this forum, so I will put this topic here (don't accuse me of putting it in the wrong place).

Ever since I started programming with Pascal I wondered about the IF construct, specifically the absence of a combined ELSE IF for elseif blocks. There are languages that use one keyword for it (VisualBASIC, Python, PHP), usually something like ELSEIF or ELSIF.

When Wirth designed the language he probably figured that backtracking or two-pass techniques, as most compilers do today, would not be an option. However, there is a way to combine the ELSE IF keywords (which would prevent the inevitable nesting of IF statements) without back tracking or doing multiple passes.

As soon as the parser finds the ELSE keyword, a fixed branch-out label can be set. It doesn't matter how many ELSE IF's will follow; they either jump to the next ELSE IF (if the condition is false) or they branch out to the fixed label. The only price to pay is a redundant label if the final ELSE IF block is not followed by a ELSE block.

To illustrate this design, here is a code snippet (not programmed in Pascal):
Code: FreeBasic  [Select]
  1. lex.getoken()
  2.        
  3. ep_evalbool()
  4.        
  5. l1 = newlabel()            ' L0
  6. emitln("JE " + l1)
  7.        
  8. st_block(el)
  9. expectoken(tkKeyword.nEnd)
  10.  
  11. ln = l1                    ' L0
  12.  
  13. if (lex.cutoken.id = tkKeyword.nElse) then
  14.        
  15.   l1 = newlabel()          ' L1 (fixed)
  16.  
  17.   do
  18.     emitln("JMP " + l1)
  19.     postlabel(ln)          ' L0, L2, L3, ...
  20.  
  21.     lex.getoken()
  22.  
  23.     if lex.cutoken.id = tkKeyword.nIf then
  24.       lex.getoken()
  25.  
  26.       ep_evalbool()
  27.  
  28.       ln = newlabel()
  29.       emitln("JE " + ln)
  30.  
  31.       st_block(el)
  32.       expectoken(tkKeyword.nEnd)
  33.  
  34.       if lex.cutoken.id <> tkKeyword.nElse then
  35.         postlabel(ln)
  36.         exit do
  37.       end if
  38.  
  39.     elseif lex.cutoken.id = tkKeyword.nDo then
  40.       st_block(el)
  41.       expectoken(tkKeyword.nEnd)
  42.       exit do
  43.     end if
  44.   loop
  45.  
  46. end if
  47.  
  48. expectoken(tkSymbol.nSemicolon)
  49.  
  50. postlabel(l1)

While slightly more complex than Pascal's IF .. THEN .. ELSE, it would still make among the fastest compilers today.
Title: Re: Syntax curiosity
Post by: marcov on September 12, 2019, 01:38:44 pm
Ever since I started programming with Pascal I wondered about the IF construct, specifically the two-keywords ELSE IF construct for elseif blocks. Most languages use one keyword for it, usually something like ELSEIF or ELSIF.

Only Basic I guess. it is a not natural combination of two keywords that already are in use. Probably they needed to fix something, but I'm not so deep into Basic details. That said, later compilable basics are not original BASIC, so it might not even be part of the original Basic syntax. Afaik C=64 Basic V2 only had if and goto.

Quote
The curious Pascal construct probably goes back to the late 60s / early 70s, when the language was first designed.

So why did Wirth choose this specific language design? When studying/developing a compiler one will see the benefit (and beauty) of it, especially when considering the available hardware at the time. In order to make a compiler fast and (relatively) simple, it should be top-down and do a single pass. But with ELSEIF blocks there is no way to know how many blocks there are, which means there is also no way to know what label to branch out to, unless the compiler does a second pass.

The whole block structure is a child of its time. Language design was in the early stages in the sixties.  He did better in the successor, Modula2, but Pascal was already a hit.

Quote
But with Wirth's clever ELSE IF construct, a fixed branch-out label can be set as soon as the parser finds the ELSE keyword. It doesn't matter how many ELSE IF's will follow; they either jump to the next ELSE IF (if the condition is false) or they branch out to the fixed label. The only price to pay is a redundant label if the final ELSE IF block is not followed by a ELSE block.

If the IF block is simple. You still need to cater for a lot of complexity if the part before the ELSE is very complex, or handle it recursively. 

Most conditional branches have very limited distances they can jump, so it nearly never this simple.


Title: Re: Syntax curiosity
Post by: Munair on September 12, 2019, 02:07:35 pm
Only Basic I guess. it is a not natural combination of two keywords that already are in use. Probably they needed to fix something, but I'm not so deep into Basic details. That said, later compilable basics are not original BASIC, so it might not even be part of the original Basic syntax. Afaik C=64 Basic V2 only had if and goto.

Not just Basic. Python has ELIF. PHP has ELSEIF to name a few. But indeed, leading languages use ELSE IF, probably for the same reason.

If the IF block is simple. You still need to cater for a lot of complexity if the part before the ELSE is very complex, or handle it recursively. 

Most conditional branches have very limited distances they can jump, so it nearly never this simple.
Recursive processing is key. Once the statements are well defined and blocks are handled properly, (deep) nesting will not be a problem.

For example:
Code: FreeBasic  [Select]
  1. ' if-statement
  2. if a = 0 do
  3.   a = fnA();
  4.   ' if-statement
  5.   if a = 1 do
  6.     a = -1;
  7.     end; ' end if-statement
  8.   end
  9. else if b = 0 do
  10.   b = fnB();
  11.   end
  12. else if c = 0 do
  13.   c = fnC();
  14.   end
  15. else if d = 0 do
  16.   d = fnD();
  17.   end
  18. else do
  19.   z = fnZ();
  20.   end; ' end if-statement

would output something like this (debugging):
Code: [Select]
if
<condition>

BEQ L0

a
BSR fnA

LEA a(PC), A0

MOVE D0, (A0)

if
<condition>

BEQ L1

a
MOVE #0, D0

LEA a(PC), A0

MOVE D0, (A0)

end
L1:
end
BRA L2

L0:
<condition>

BEQ L3

fnB
BSR fnB

end
BRA L2

L3:
<condition>

BEQ L4

fnC
BSR fnC

end
BRA L2

L4:
<condition>

BEQ L5

fnD
BSR fnD

end
BRA L2

L5:
fnZ
BSR fnZ

end
L2:
EOI

I find AST processing much more complex than recursive procedure handling.
Title: Re: Syntax curiosity
Post by: marcov on September 12, 2019, 02:13:19 pm
Well, Pascal is not that simple, compare:

Code: Pascal  [Select]
  1. if a then
  2.   if b then
  3.       s
  4.     else
  5.       s2
  6.  
  7. with
  8.  
  9. if a then
  10.   if b then
  11.       s;
  12.  else
  13.    s2
  14.  
  15.  

I tried to illustrate the difference with indentation (which the compiler of course ignores)
Title: Re: Syntax curiosity
Post by: Munair on September 12, 2019, 02:33:16 pm
Well, Pascal is not that simple, compare:

Code: Pascal  [Select]
  1. if a then
  2.   if b then
  3.       s
  4.     else
  5.       s2
  6.  
  7. with
  8.  
  9. if a then
  10.   if b then
  11.       s;
  12.  else
  13.    s2
  14.  
  15.  

I tried to illustrate the difference with indentation (which the compiler of course ignores)

Well, I suppose that's where BEGIN .. END come in to prevent potential ambiguity and also make the code better readable / understandable. In general, a language should leave no room for ambiguity (which may be among the hardest parts of compiler development).
Title: Re: Syntax curiosity
Post by: 440bx on September 12, 2019, 03:05:17 pm
Ever since I started programming with Pascal I wondered about the IF construct, specifically the two-keywords ELSE IF construct for elseif blocks. Most languages use one keyword for it, usually something like ELSEIF or ELSIF.

The curious Pascal construct probably goes back to the late 60s / early 70s, when the language was first designed.
It's a bit amusing to see the Pascal if/then/else construct described as "curious".

In a language that has the if/else construct, an "elseif", or any other syntactic variant thereof, is an indication of poor language design.  First, it's completely redundant/unnecessary.  Second, imagine if there was an "elsefor" or "elsewhile", etc, that would legitimately be "curious". An "elseif" construct is as curious as any of those yet, programmers don't see it that way because it allows them to indulge in one of their most common poor programming practices, that is, deeply nested if/else constructions.  A very poor programming habit made even worse by the "preference" some programmers have not to align begin/end pairs.

"elseif"/"elsif" is simply "cheap design" that caters to poor programming.



Title: Re: Syntax curiosity
Post by: MarkMLl on September 12, 2019, 03:21:23 pm
Picking up on OP's

> Well, I suppose that's where BEGIN .. END come in to prevent potential ambiguity

More to the point, that's where Modula-2's IF .. THEN .. END (the END being mandatory) comes in. However how it got there is worth examining.

ALGOL-60 and ALGOL-W both used the Pascal-style  if <expression> then <single statement>  form. ALGOL-68 uses  if <expression> then <statement sequence> end  which eliminates the dangling-else problem. Wirth, as is well known, resigned from the ALGOL-68 standardisation process and shortly afterwards introduced Pascal, apparently intentionally breaking the ALGOL syntax by- as a specific example- changing the order of variable declaration. In addition to this, the earliest Pascal specification used /* */ for comments but Wirth gives the impression of having switched to (* *) when he noticed that he was suggesting compatibility with the B language.

Wirth fixed the dangling else problem in Modula-2, and it's also fixed in Ada (which is not, as a result, a "Pascal style" language whatever the unwashed say).

To its discredit, Pascal- as designed by Wirth with input from Hoare- has  record .. end  and  case .. end. The  then <single statement>  form might be excusable if ALGOL's  := if <expression> then <expression> else <expression>  form had been retained, but for some reason Wirth jettisoned it.

So I know that plenty of people are going to object to my saying this, but Pascal's syntax is a mess.

MarkMLl
Title: Re: Syntax curiosity
Post by: Munair on September 12, 2019, 03:51:40 pm
It's a bit amusing to see the Pascal if/then/else construct described as "curious".

In a language that has the if/else construct, an "elseif", or any other syntactic variant thereof, is an indication of poor language design.  First, it's completely redundant/unnecessary.  Second, imagine if there was an "elsefor" or "elsewhile", etc, that would legitimately be "curious". An "elseif" construct is as curious as any of those yet, programmers don't see it that way because it allows them to indulge in one of their most common poor programming practices, that is, deeply nested if/else constructions.  A very poor programming habit made even worse by the "preference" some programmers have not to align begin/end pairs.

"elseif"/"elsif" is simply "cheap design" that caters to poor programming.
I wasn't referring to " IF..THEN.ELSE" but to "ELSE IF". Python and PHP are widely used and support exactly this "poor" ELIF and ELSEIF design. I wouldn't call it poor per se, but from a compiler development point of view it requires more steps only to satisfy potential programmers' preference. As far as I can trace it back, the ELSEIF clause was introduced in the 1980s (at least with QuickBASIC) when computers became more powerful and back tracking and 2-pass techniques became acceptable techniques.
Title: Re: Syntax curiosity
Post by: Munair on September 12, 2019, 03:57:38 pm
So I know that plenty of people are going to object to my saying this, but Pascal's syntax is a mess.
I partially agree. But regarding the two-keywords ELSE IF construct, it is found in leading programming languages, and from a compiler construction point of view, it is logical. This is exactly the reason why every serious programmer should know at least SOMETHING about compiler design.
Title: Re: Syntax curiosity
Post by: 440bx on September 12, 2019, 04:11:00 pm
I wasn't referring to " IF..THEN.ELSE" but to "ELSE IF".
I see what you're saying now.  I guess/believe that Wirth chose the "ELSE IF" syntax because things like "elseif"/"elif" are redundant when there is "IF" and "ELSE". 


So I know that plenty of people are going to object to my saying this, but Pascal's syntax is a mess.
I'd say its got a few quirks but, I wouldn't describe the Pascal syntax as a mess.  Unlike in other languages, some very popular ones, there are very few ways in Pascal of messing things up due to a syntactically unintended construct.
Title: Re: Syntax curiosity
Post by: Munair on September 12, 2019, 04:18:12 pm
I guess/believe that Wirth chose the "ELSE IF" syntax because things like "elseif"/"elif" are redundant when there is "IF" and "ELSE".

If ELSEIF could be implemented with the same ease and performance there would be no reason not to do so, except that it would add another keyword.
Title: Re: Syntax curiosity
Post by: MarkMLl on September 12, 2019, 04:19:38 pm
I partially agree. But regarding the two-keywords ELSE IF construct, it is found in leading programming languages, and from a compiler construction point of view, it is logical. This is exactly the reason why every serious programmer should know at least SOMETHING about compiler design.

Modula-2 has ELSIF. Can't remember whether the original Modula had it.

The idea of  if <expression> then <single statement>  and so on, which was what necessitated  begin ... end  , is fine as far as elegance is concerned. But I don't think that reputable languages provide a more urgent example of the gulf between elegant and reliable.

Leaving aside the reliability issue of that form, it was an utter sod to explain in documentation in the days when most programming was done with punched cards and indented sourcecode was a comparative rarity. I suggest that anybody who doesn't believe me digs into early ALGOL manuals on Bitsavers.

My own suspicion is that Wirth was intent on producing Pascal quickly, so that he could present the community with a fait accompli before the ALGOL-68 standardisation effort had wound down. And I also suspect that his compiler writing technique in that era, which if Euler is anything to go by involved uncommented numeric tables and- yes- GOTOs, was sufficiently resistant to modification that he recognised that fixing the if statement's flaws without introducing additional problems was something to not be undertaken lightly.

MarkMLl
Title: Re: Syntax curiosity
Post by: MarkMLl on September 12, 2019, 04:33:10 pm
I'd say its got a few quirks but, I wouldn't describe the Pascal syntax as a mess.  Unlike in other languages, some very popular ones, there are very few ways in Pascal of messing things up due to a syntactically unintended construct.

It appears to me that, 50 years on, most language designers are struggling to match Pascal's support for string handling and moderately strong type checking without leaving themselves open to accusations they're trying to persuade the World to program in Pascal.

But I'm afraid that I stick to my guns here and say that Pascal's mix of elegant if (not terminated by end) and reliable case (terminated by end) is a mess.

MarkMLl
Title: Re: Syntax curiosity
Post by: Munair on September 12, 2019, 05:16:17 pm
I almost forgot, RPG is another language that uses ELSEIF. Doing some more reading, it seems the 2-keywords ELSE IF construct can confuse programmers as to what belongs to what; does the IF belong to the ELSE or is it a new IF statement (it shouldn't be). Marcov's example demonstrates how confusing and harder-to-read it can get.

In my opinion constructs like
Code: Pascal  [Select]
  1. if <condition> then
  2.   if <condition> then
  3.     <consequence>
  4. else
  5.   consequence;
should not be possible.

Rather:
Code: FreeBasic  [Select]
  1. if <condition> do
  2.   if <condition> do
  3.     <consequence>;
  4.     end; 'nested statement end
  5. else
  6.   <consequence>;
  7.   end; ' statement end
whereby the statement ends are mandatory and the semicolon leaves no doubt as to which statement (block) is which.
Title: Re: Syntax curiosity
Post by: ArtLogi on September 12, 2019, 10:41:33 pm
Interesting topic. I had to actually go and try if "ELSE IF" could be written as

Code: Pascal  [Select]
  1. IF arg1 oper arg2 THEN
  2.   statement
  3. ELSE
  4. IF arg1 oper arg2 THEN
  5.  statement
  6. ELSE
  7.  
Nope... but is this logically the same as IF - ELSE IF - ELSE?
Code: Pascal  [Select]
  1. BEgin
  2.         if 1=0 then begin
  3.                writeln('1=0')
  4.           end
  5.         elsE begin
  6.               IF 1=2 THEN begin
  7.                  WRITELN('1=2')
  8.                 end
  9.                ELSE begin
  10.                      WRITELN('else')
  11.                 end
  12.            end
  13. End.
... because if you do count there is exactly same amount of words IF and ELSE than statement of IF - ELSE IF - ELSE

That said isn't the "original" Wirth Pascal requiring begin and end to each instruction with no exception see next post. The question needs to be analysed in the light (because it is asked as) of the original Wirth implentation of Pascal, not a modern streamlined and extended ones?
Title: Re: Syntax curiosity
Post by: winni on September 12, 2019, 10:57:59 pm
The original Wirth syntax said:

After every then or else is exact one statement allowed. If there are more then one statement you have to enclose them with begin ... end;

So this is allowed:

Code: Pascal  [Select]
  1. If c = clBlue then doSomeThing else
  2. if c = clLime then doAnotherThing else
  3. if c = clRed then PaintItRed else
  4.   begin
  5.   MixedColors;
  6.   canvas.TextOut (10,10,'Mixed Colors');
  7.   end;
  8.  
  9.  

Winni

Title: Re: Syntax curiosity
Post by: ArtLogi on September 12, 2019, 11:45:47 pm
The original Wirth syntax said:

After every then or else is exact one statement allowed. If there are more then one statement you have to enclose them with begin ... end;

So this is allowed:

Code: Pascal  [Select]
  1. If c = clBlue then doSomeThing else
  2. if c = clLime then doAnotherThing else
  3. if c = clRed then PaintItRed else
  4.   begin
  5.   MixedColors;
  6.   canvas.TextOut (10,10,'Mixed Colors');
  7.   end;
  8.  
  9.  

Winni
Nice :)

Just for curiosity here is example of Forth (Stack based postfix language), replace DUP with any number (DUP is stack command = Duplicate last returned value/object). This makes much more sense than infix IFs:
Code: Text  [Select]
  1. : EGGSIZE
  2.    DUP 18 < IF  ." reject "      ELSE
  3.    DUP 21 < IF  ." small "       ELSE
  4.    DUP 24 < IF  ." medium "      ELSE
  5.    DUP 27 < IF  ." large "       ELSE
  6.    DUP 30 < IF  ." extra large " ELSE
  7.       ." error "
  8.    THEN THEN THEN THEN THEN DROP ;
From https://www.forth.com/starting-forth/4-conditional-if-then-statements/
Title: Re: Syntax curiosity
Post by: winni on September 13, 2019, 12:57:40 am
Gosh! Forth - I haven't used it for 30 years. When the PCs were awful slow, then Forth was fast as lightning. But I hate postfix notations - the same hassle as with PostScript.

And for the quintuple of "THEN" the should invent something shorter. Perhaps "THEN * 5".
Title: Re: Syntax curiosity
Post by: 440bx on September 13, 2019, 01:43:17 am
This discussion about the chained if/else reminded me of how nicely that construct is implemented in COBOL85 and above.

In COBOL a programmer can simply have
Code: ASM  [Select]
  1. EVALUATE TRUE
  2.   WHEN <conditional expression 1>
  3.     <statements applicable to above condition>
  4.  
  5.   WHEN <conditional expression 2>
  6.     <statements applicable to above condition>
  7.  
  8.   WHEN <conditional expression n>
  9.     <statements applicable to above condition>
  10.  
  11.   WHEN OTHER
  12.     <statements applicable to above condition>
  13. END-EVALUATE
  14.  
fully linear and prioritized by the test sequence.  In addition to that, it allows multiple conditions to be tested making the implementation of logical tables simple and really easy to understand and maintain.  It's also possible to evaluate against FALSE, which can occasionally be very convenient.

That statement can easily be synthesized in Pascal using a nested procedure (or nested function if convenient) but, it is extremely rare to see it done that way.  Instead, long series of "else if" are all too common.

Title: Re: Syntax curiosity
Post by: jamie on September 13, 2019, 02:26:57 am
Forth wasn't so bad, I participated in a camera view project to detect defected package via a camera and operate a push rode to eject it from the packing line.

 The idea was to test for  a defective label where as the label and bottle was almost the same color using Black and White camera.

  Did that on a Z80 processing box using forth and some Zilog Asm..
Title: Re: Syntax curiosity
Post by: winni on September 13, 2019, 02:45:32 am
No - Forth wasn't bad. I liked the concept. And the speed. But I struggled with the postfix notation.

Z80 (Unused! Brandnew!) you can buy for 1.30 $. At Ebay. "Play it again, Sam ......"
Title: Re: Syntax curiosity
Post by: Munair on September 13, 2019, 07:01:20 am
This discussion about the chained if/else reminded me of how nicely that construct is implemented in COBOL85 and above.

In COBOL a programmer can simply have
Code: ASM  [Select]
  1. EVALUATE TRUE
  2.   WHEN <conditional expression 1>
  3.     <statements applicable to above condition>
  4.  
  5.   WHEN <conditional expression 2>
  6.     <statements applicable to above condition>
  7.  
  8.   WHEN <conditional expression n>
  9.     <statements applicable to above condition>
  10.  
  11.   WHEN OTHER
  12.     <statements applicable to above condition>
  13. END-EVALUATE
  14.  
fully linear and prioritized by the test sequence.  In addition to that, it allows multiple conditions to be tested making the implementation of logical tables simple and really easy to understand and maintain.  It's also possible to evaluate against FALSE, which can occasionally be very convenient.

That statement can easily be synthesized in Pascal using a nested procedure (or nested function if convenient) but, it is extremely rare to see it done that way.  Instead, long series of "else if" are all too common.

I wouldn't recommend synthesizing such construct using procedures because it would be much less optimal with the added stack frames. Elegance is nice but not at the cost of less optimal code.
Title: Re: Syntax curiosity
Post by: 440bx on September 13, 2019, 07:49:31 am
I wouldn't recommend synthesizing such construct using procedures because it would be much less optimal with the added stack frames. Elegance is nice but not at the cost of less optimal code.
You're right in that there is an added stack frame in that case but, the loss of performance is negligible and, only perceptible if the procedure is executed extremely often.

I consider code simplicity and maintainability much more important than performance.  I only pay attention to performance when it gets in the way of usability, i.e, jerky or "elastic" user interface and that kind of thing.   (The Windows API DrawText, used by Listview controls and wsprintf in user32 are in that category, their performance is dismal.)

ETA:

It's quite likely that such a procedure could be inlined thus eliminating the stack frame and performance considerations.  I haven't tried it but, it seems quite reasonable.



Title: Re: Syntax curiosity
Post by: PascalDragon on September 13, 2019, 09:50:56 am
Ever since I started programming with Pascal I wondered about the IF construct, specifically the two-keywords ELSE IF construct for elseif blocks. There are languages that use one keyword for it (VisualBASIC, Python, PHP), usually something like ELSEIF or ELSIF.
It's rather simple: Pascal does not have an ELSE IF construct. It simply has another if ... then (... else) statement inside the else-branch of an if-statement (or the then-branch). This reduces complexity in the parser, cause then it's just a chain of if-statements.
Title: Re: Syntax curiosity
Post by: Thaddy on September 13, 2019, 10:01:12 am
Pascal has case....
Title: Re: Syntax curiosity
Post by: Munair on September 13, 2019, 12:17:15 pm
Ever since I started programming with Pascal I wondered about the IF construct, specifically the two-keywords ELSE IF construct for elseif blocks. There are languages that use one keyword for it (VisualBASIC, Python, PHP), usually something like ELSEIF or ELSIF.
It's rather simple: Pascal does not have an ELSE IF construct. It simply has another if ... then (... else) statement inside the else-branch of an if-statement (or the then-branch). This reduces complexity in the parser, cause then it's just a chain of if-statements.

Yes, code ordered nicely in this manner:

Code: Pascal  [Select]
  1. if a then
  2.   someA()
  3. else if b then
  4.   someB()
  5. else if c then
  6.   someC();

would logically be:

Code: Pascal  [Select]
  1. if a then
  2.   someA()
  3. else
  4.   if b then
  5.     someB()
  6.   else
  7.     if c then
  8.       someC();

People new to Pascal may confuse the first coding habit with C-like syntax where the ELSE IF combination (outside braces) actually is treated as a single statement.
Title: Re: Syntax curiosity
Post by: 440bx on September 13, 2019, 01:14:46 pm
Pascal has case....
but a case statement cannot be used to replace an if/else chain.

Title: Re: Syntax curiosity
Post by: howardpc on September 13, 2019, 01:43:46 pm
Pascal has case....
but a case statement cannot be used to replace an if/else chain.
Nested case statements can replace an if/else chain, and are usually clearer, if more verbose.
Title: Re: Syntax curiosity
Post by: 440bx on September 13, 2019, 02:03:30 pm
Nested case statements can replace an if/else chain, and are usually clearer, if more verbose.
I don't see how it could be done when the if statements compare an expression to another expression.  A case statement requires an expression to be compared with constant values.  I don't see how that limitation can be circumvented even with nested case statements.
Title: Re: Syntax curiosity
Post by: howardpc on September 13, 2019, 02:31:29 pm
I have in mind constructs of this sort
Code: Pascal  [Select]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. type
  6.   TCategory = (Less, Equal, Greater);
  7.  
  8.   function Categorise(aValue, aBoundary: Integer): TCategory;
  9.   begin
  10.     if aValue < aBoundary then
  11.       Result := Less
  12.     else if aValue = aBoundary then
  13.       Result := Equal
  14.     else if aValue > aBoundary then
  15.       Result := Greater;
  16.   end;
  17.  
  18.   function CategoriseCase(aValue, aBoundary: Integer): TCategory;
  19.   begin
  20.     case aValue < aBoundary of
  21.       True: Exit(Less);
  22.       False: case aValue > aBoundary of
  23.         True: Exit(Greater);
  24.         False: Exit(Less);
  25.       end;
  26.     end;
  27.   end;
  28.  
  29. var
  30.   value: Integer;
  31.  
  32. begin
  33.   WriteLn('Categorise(10, 99) = ',Categorise(10, 99));
  34.   WriteLn('Categorise(99, 99) = ',Categorise(99, 99));
  35.   WriteLn('Categorise(100, 99) = ',Categorise(100, 99));
  36.   WriteLn;
  37.   WriteLn('CategoriseCase(10, 99) = ',Categorise(10, 99));
  38.   WriteLn('CategoriseCase(99, 99) = ',Categorise(99, 99));
  39.   WriteLn('CategoriseCase(100, 99) = ',Categorise(100, 99));
  40.   ReadLn;
  41. end.

One slight advantage of case over if/then/else is that when repeated millions of times for the same operation, case is usually slightly faster.
Title: Re: Syntax curiosity
Post by: Zvoni on September 13, 2019, 02:47:53 pm
I agree with Thaddy.

The "ElseIf" i know from VisualBasic (Classic Version 6, not Dot Crap!) is a way to narrow down the consequences if the initial Condition is not met.
"If Condition Then
Consequence1
ElseIf Condition2 Then
Consequence2
End"

In a "Standard" If-Then-Else construct something like a=4, A=7, A=123456
"If a=1 Then
Consequence1
Else
Consequence2
End"
Consequence2 would be executed for all values a<>1

with the "ElseIf" i can narrow down the filter for which Consequence2 should fire.

But in that case i'd rather use a "Case of"-Statement, which is alo available in VisualBasic
"Select Case a
Case 1
Consequence1
Case 4
Consequence2
Case 5
Consequence3
Case Else
NukeWhiteHouse
End Select"
And no, no arguing about Syntax-Beauty now :-)
Agree with Thaddy: Use "Case"
Title: Re: Syntax curiosity
Post by: Munair on September 13, 2019, 03:12:20 pm
There is an important difference between IF and CASE:

Code: FreeBasic  [Select]
  1. if a = 1 then
  2.   ...
  3. elseif b = 1 then
  4.   ...
Title: Re: Syntax curiosity
Post by: 440bx on September 13, 2019, 03:27:26 pm
One slight advantage of case over if/then/else is that when repeated millions of times for the same operation, case is usually slightly faster.
Yes, because in the example you showed the compiler can create a jump table based on the variable's value but, a jump table can only be created when a single expression is compared against constants.  That's one of the very significant limitations of the case statement, the inability to compare one expression against another.

The other significant limitation that @Munair pointed out above is, a case statement can only handle a single expression.  If the logic depends on multiple expressions, a case statement cannot handle that.

COBOL's EVALUATE statement does not have those limitations and that statement really helps write some very clean, easy to understand and maintain code.  I know it won't happen but, it would be a very nice addition to the Pascal language ("Pascalized" of course.)

Title: Re: Syntax curiosity
Post by: Zvoni on September 13, 2019, 05:46:36 pm
In VB i could do this:
Select Case True
Case a=1
DoSomething1
Case b=3
DoSomethingElse
Case Else
KABOOM
End Select

Is there an equivalent in Pascal?
Title: Re: Syntax curiosity
Post by: dsiders on September 13, 2019, 06:00:00 pm
In VB i could do this:
Select Case True
Case a=1
DoSomething1
Case b=3
DoSomethingElse
Case Else
KABOOM
End Select

Is there an equivalent in Pascal?

https://www.freepascal.org/docs-html/ref/refsu56.html
Title: Re: Syntax curiosity
Post by: Zvoni on September 13, 2019, 06:04:04 pm
Seems that‘s a no.
Pity, i do like it
And FWIW: In VB the Select Case is fallthrough!
Title: Re: Syntax curiosity
Post by: howardpc on September 13, 2019, 06:35:38 pm
In VB i could do this:
Select Case True
Case a=1
DoSomething1
Case b=3
DoSomethingElse
Case Else
KABOOM
End Select

Is there an equivalent in Pascal?
Would this fit the bill?
Code: Pascal  [Select]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5.   procedure DoSomething1;
  6.   begin
  7.     WriteLn('DoSomething1');
  8.   end;
  9.  
  10.   procedure DoSomethingElse;
  11.   begin
  12.     WriteLn('DoSomethingElse');
  13.   end;
  14.  
  15.   procedure Kaboom;
  16.   begin
  17.     WriteLn('Kaboom');
  18.   end;
  19.  
  20.   procedure Choose(a, b: Integer);
  21.   begin
  22.     case (a = 1) of
  23.       True: DoSomething1;
  24.       False: case (b = 3) of
  25.                True: DoSomethingElse;
  26.                False: Kaboom;
  27.              end;
  28.     end;
  29.     WriteLn;
  30.   end;
  31.  
  32. var
  33.   a, b: Integer;
  34.  
  35. begin
  36.   a := 0;
  37.   b := 0;
  38.   Choose(a, b);
  39.   a := 1;
  40.   Choose(a, b);
  41.   a := 2;
  42.   b := 3;
  43.   Choose(a, b);
  44.   ReadLn;
  45. end.
Title: Re: Syntax curiosity
Post by: Zvoni on September 13, 2019, 09:25:18 pm
Howard, thx, but it‘s not of urgent importance to me right now, but i appreciate your effort
Title: Re: Syntax curiosity
Post by: MarkMLl on September 19, 2019, 10:22:32 am
The original Wirth syntax said:

After every then or else is exact one statement allowed. If there are more then one statement you have to enclose them with begin ... end;

Note that that wasn't a Wirth thing, that was an ALGOL-60 thing and there was also a variant like

a := if b: then c else d

which is all nice and orthogonal. But at some point before the ALGOL-68 standardisation process it was recognised that that syntax, no matter how elegant, was also susceptible to the dangling-else problem... note that I'm not calling it an ambiguity, but it's definitely a problem.

Wirth perpetuated the ALGOL-60 <single statement> form, when he could (and later did) fix it by adopting  if <condition> then <statement sequence> end  etc. He dropped the in-expression form despite this not being necessary (for the sake of consistency) until the statement form was fixed. And he introduced records etc. which had an explicit end, rather than themselves needing a begin...end pair. In short, whatever his reputation as a pragmatist, Pascal's syntax is messily inconsistent.

In ALGOL-60, begin...end was also used for the entire program (i.e. rather than program...end). Also variables were declared inside blocks rather than before them, the idea of moving declarations to before the  begin  would be all very well if it didn't preclude declaring temporary index variables for the  for  statement rather than leaving things as "this value becomes undefined".

So I'm sorry, but whatever the efforts of people over the years Pascal as defined by Wirth was flawed.

MarkMLl


Title: Re: Syntax curiosity
Post by: 440bx on September 19, 2019, 01:21:45 pm
But at some point before the ALGOL-68 standardisation process it was recognised that that syntax, no matter how elegant, was also susceptible to the dangling-else problem... note that I'm not calling it an ambiguity, but it's definitely a problem.
It's not a "problem", it is a consequence of the language not requiring explicit statement terminators for some constructs, e.g, if <statements> fi, or case <statements> esac.  The lack of explicit statement terminators is what causes the dangling else "problem".

he introduced records etc. which had an explicit end, rather than themselves needing a begin...end pair. In short, whatever his reputation as a pragmatist, Pascal's syntax is messily inconsistent.
There is no inconsistency, what there is, is the elimination of superfluous syntactic elements.  "record", "repeat" or "case" do not need begin/end pairs because they are by design <field>/<statement> containers, therefore requiring begin/end pairs in those statements would be superfluous and only add unnecessary clutter to the language.

So I'm sorry, but whatever the efforts of people over the years Pascal as defined by Wirth was flawed.
Every design has its own set of implications, that doesn't mean the design is flawed (though in some cases, it could.)

The Pascal language is very well designed. 
Title: Re: Syntax curiosity
Post by: marcov on September 19, 2019, 01:31:22 pm
But at some point before the ALGOL-68 standardisation process it was recognised that that syntax, no matter how elegant, was also susceptible to the dangling-else problem... note that I'm not calling it an ambiguity, but it's definitely a problem.
It's not a "problem", it is a consequence of the language not requiring explicit statement terminators for some constructs, e.g, if <statements> fi, or case <statements> esac.  The lack of explicit statement terminators is what causes the dangling else "problem".

Yes and no. It is the ambiguity of one or more statements.  Statement terminators are not necessary for if <cond> then <block> [else <block>]  simply because the block already is terminated with END. Then the else option is just one token lookahead.

Quote
The Pascal language is very well designed.

Which is probably why Wirth made the changes that Mark describes in his next languages Modula-*
Title: Re: Syntax curiosity
Post by: MarkMLl on September 19, 2019, 03:32:43 pm
The point I was trying to make was that dangling else is not an ambiguity as far as the language design was concerned: there is a robust rule which results in the parser always making the same choice when confronted by the same sequence of constructs.

But even though it's not a syntactic ambiguity, it is undoubtedly a problem in that it allows an inattentive (aka busy) or inexperienced user to write code which doesn't behave as he intended.

I for one would love it if that wasn't the case. I'd love it if something like the  if <conditional> then <single statement>  and so on form could be applied in all cases, and for consistency that includes data definition (after all, "Algorithms + Data Structures = Programs" implies that the notation should be orthogonal).

On the other hand, if you design a language to use  if <conditional> then <statement sequence> end  and so on, then you have some chance of implementing it with  begin <statement sequence> end  minimised to the point where a naive compiler can assume that it represents stackframe manipulation: something that generally isn't needed by simple structured program control flow.

MarkMLl
Title: Re: Syntax curiosity
Post by: Munair on September 20, 2019, 07:27:25 pm
But even though it's not a syntactic ambiguity, it is undoubtedly a problem in that it allows an inattentive (aka busy) or inexperienced user to write code which doesn't behave as he intended.

I can confirm that this is indeed the case with Pascal. However, we have to bear in mind the time that the language was developed. Compiler construction was in its infancy and over time significant and important improvements were implemented in successive languages that borrowed from the early greats such as Pascal. And here we touch upon the reason for developing new languages as the old ones almost always stick to their early definitions and rarely undergo syntax improvements that could lift them to modern standards.
Title: Re: Syntax curiosity
Post by: Munair on September 20, 2019, 07:46:30 pm
[Statement terminators are not necessary for if <cond> then <block> [else <block>]  simply because the block already is terminated with END. Then the else option is just one token lookahead.
Pascal doesn't have statement terminators. It has statement separators, which is not the same (yes, quite confusing). IMO statement terminators serve a better purpose in that they make it clear where a statement starts and where it ends, especially with (nested) IF blocks. Because in Pascal the semicolon is used as a statement separator, it often leads to null statements because (even experienced) programmers use it where it is not required. That is one issue I would like to tackle in a new Pascal-like language; it shouldn't leave any room for ambiguity.
Title: Re: Syntax curiosity
Post by: MarkMLl on September 20, 2019, 08:46:04 pm
However, we have to bear in mind the time that the language was developed. Compiler construction was in its infancy and over time significant and important improvements were implemented in successive languages that borrowed from the early greats such as Pascal. And here we touch upon the reason for developing new languages as the old ones almost always stick to their early definitions and rarely undergo syntax improvements that could lift them to modern standards.

Yes but: Wirth was on the ALGOL-68 standardisation committee, and ALGOL-68 fixed the dangling else problem using the solution eventually adopted by Wirth in Modula-2 (I'm not sure the standing of Modula(-1) with regards to this). It was also fixed in Ada, with which AIUI Wirth was involved as a consultant.

ALGOL-W had an ALGOL-60 style notation, and as such was susceptible to dangling else. Now Wirth might have been trying to avoid departing from ALGOL-60's gross syntax when he introduced Pascal, but in that case why did he- as a specific example- move the type in a variable declaration to the right of the name? If he broke the syntax by doing that for no obvious reason, why didn't he fix dangling-else at the same time since he undeniably knew that it was a problem?

MarkMLl
Title: Re: Syntax curiosity
Post by: Thaddy on September 21, 2019, 01:45:04 pm
Pascal has case....
but a case statement cannot be used to replace an if/else chain.
Apart from nesting: no. But there are other options that are overlooked here.
Consider:
Code: Pascal  [Select]
  1. var
  2.   i:integer = 0;
  3. begin
  4.   if i in [0..3, 7, 9, 12..15] then { do something };
  5. end.
Since i is here not a loop variable, but a plain ordinal, it is even allowed to modify it.
You can use this to construct C like switch w/o breaks for example.
Title: Re: Syntax curiosity
Post by: valdir.marcos on September 21, 2019, 03:12:15 pm
Pascal has case....
but a case statement cannot be used to replace an if/else chain.
Apart from nesting: no. But there are other options that are overlooked here.
Consider:
Code: Pascal  [Select]
  1. var
  2.   i:integer = 0;
  3. begin
  4.   if i in [0..3, 7, 9, 12..15] then { do something };
  5. end.
Since i is here not a loop variable, but a plain ordinal, it is even allowed to modify it.
You can use this to construct C like switch w/o breaks for example.
Interesting.