7

Most Pascal control structures make sense to me, like:

for ... do {statement};

if (condition) then {statement};

while (condition) do {statement};

where the {statement} is either a single statement, or a begin ... end block. I have a problem with:

repeat {statement-list} until (expression);

try {statement-list} except {statement-list} end;

Wouldn't it be better that repeat and try have the same general structure, accepting only a single statement or a begin ... end block, instead of having a statement-list that's not formally blocked with a begin and an end?

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
70Mike
  • 304
  • 2
  • 12
  • 1
    I've made the mistake of asking two questions here - "Why are pascal control structures inconsistent?", then in the body of the text, asking "Wouldn't it be better?". Now that there are excellent answers to both, do I edit this and create another question for the other answer? What's the preferred StackOverflow way of dealing with this? – 70Mike Jan 07 '11 at 01:04
  • you are completely missing compound statement concept, which is zero or more statements surrounded by begin..end – Free Consulting Jan 07 '11 at 04:00
  • @Mike: you seem to ask this because of a code formatter; maybe you want to extend this question (http://stackoverflow.com/questions/402737/delphi-code-formatter) or ask a new question about a code formatter that supports new language features (class vars, class consts, generics) well. – Jeroen Wiert Pluimers Jan 07 '11 at 07:10
  • 2
    @70Mike As Greg Hewgill points out, this is something that Wirth corrected in Modula-2 and all his subsequent languages. I believe the the single/compound statement distinction, a carry over from Algol, is one his biggest regrets over Pascal. The inconsistency of single/compound statement leads to programmer errors. The simple clarity in Modula-2 is the *right* solution to the problem. – David Heffernan Jan 07 '11 at 09:09
  • 2
    @70Mike (continued) My company's product was formerly implemented in Modula-2 using the TopSpeed compiler which later became Clarion. When we ported to Delphi (out of necessity due to lack of support from TopSpeed) we introduced coding standards that banned the use of single statements. All our if/for/while statements have begin/end blocks. I'm convinced that this was an excellent decision and the rule remains in place today. – David Heffernan Jan 07 '11 at 09:11
  • @David: "we introduced coding standards that banned the use of single statement" a perfect example of what coding standards should NOT do. i.e. eliminate the need for programmers to *think* about what they are doing... just always use being/end and you will be fine, rather than thinking "is it safe/reliable/reasonable/clear to do what I'm doing here?". Ditto any coding standard that imposes "Hungarian" notation and local variable prefixes on variable names, rather than a simple "variables must be named clearly and meaningfully" rule, which is all you really need. – Deltics Feb 10 '11 at 20:07
  • @Jeroen: Inconsistent == Not consistent. But imho, "always the same" <> "consistent". Therefore inconsistent <> "not always the same", which is what David appears to work to. Example: When my children ask permission to do things I sometimes reply yes, I sometime reply no: not the same answer every time, but the rules I apply in giving any one answer are consistent. – Deltics Feb 10 '11 at 20:09
  • @Deltics Actually the constraints that the coding standard imposes allows us to expend more time thinking about the real problem. – David Heffernan Feb 10 '11 at 20:11
  • @Deltics, @David: I agree with both of you. Standards are needed so you can focus your thinking on the important aspects of your software. But they should not suffocate you. – Jeroen Wiert Pluimers Feb 10 '11 at 20:34
  • @David - the point is that many people end up worrying more about coding to the standards than they do about thinking about the business problem. Stimulating thinking always has better results than over-prescriptive code standards, ime. – Deltics Feb 11 '11 at 02:15
  • @David supplemental: It may be a "way out there" example, but I think the same process can be seen at work in Montana. When they introduced numerical speed limits, accident rates doubled (previously the speed limit was "safe and reasonable"). Theory: Without numerical limits, people had to think about what "safe and reasonable speed" was for their vehicle, their ability and the conditions. With numerical limits, they could just concentrate on the "business problem" (getting from A to B) and go as fast as the limit allowed. Result: *More* accidents in the "business solution", not less. :) – Deltics Feb 11 '11 at 02:17
  • Hmm, I realise my previous-but-one comment could be considered to contradict itself... so to clarify... the point I was trying to make is that many people switch off their brain in the presence of the "safety blanket" of a prescriptive coding standard. As long as the code ticks the highly detailed boxes in the standard, all is well with the world. So they end up thinking less *overall*. In my experience, highly prescriptive standards are less successful overall than what others might see as "more relaxed" ones. ymmv – Deltics Feb 11 '11 at 02:23
  • @deltics It's just code formatting. All sane teams, even with one member, agree on standard formatting. This allows everyone to read the code easily. I'll bet that you use a standard formatting. For example I'll bet all your code is indented the same way. But why are you so prescriptive? Why don't you relax this safety blanket and use different indentation to suit each method? – David Heffernan Feb 11 '11 at 07:58
  • @David - no, all sane developers agree that rejecting valid code because it does not conform to an arbitrary formatting standard that add's nothing of use is a waste of everybody's time. It wastes review time by having to check conformance, it wastes developer time by having to reformat valid code from valid in format X to valid in format Y OR it wastes developer time in having to continually adjust formatting during development (a *distraction* from the business problem). – Deltics Feb 11 '11 at 10:08
  • @David again: Consistent indentation is not the same as arbitrarily mandating "begin/end". Yes, if different indents are used in the same method, then for sure it will be tidied up, but not against some arbitrary "Gold Standard" indent number, just made internally consistent to that method. My code standard says "use consistent and clear indentation", it does not say "indent a 3 character margin then 2 characters for each further indentation to a maximum of 8 levels of indentation deep. If further indentation is required then refactor" (and yes I have seen such standards). – Deltics Feb 11 '11 at 10:12
  • @Deltics You've got double standards if you think indentation is different from what I'm talking about! What's more there's never any checking and rejecting of code due to our begin/end rule because it never gets broken. It works for us. – David Heffernan Feb 11 '11 at 10:24
  • @David: If someone forgets to begin/end a single statement you have to return it for rework for non-compliance. And whilst neither indentation nor unnecessary begin/end pairs do anything for code "correctness", they are quite different in effect on readability. Consistent indentation aids it, unnecessary begin/end impairs it (100% disambiguation <> improved readability). – Deltics Feb 13 '11 at 20:16
  • @deltics no, if I spot it I just fix it on the spot. Takes 20s tops. Never happens anyway. – David Heffernan Feb 13 '11 at 20:47
  • @David - Either you "fix it on the spot" and you know how long it takes, or it never happens ... which is it? I really don't think you can have it both ways. ;) – Deltics Feb 14 '11 at 01:11
  • @deltics if I see it I fix it. If I don't see it it stays as is. It's just like an if/else or do you deny their existence? – David Heffernan Feb 14 '11 at 07:37

7 Answers7

9

The forms that require a begin/end all exist on a single line--the compiler has no other way to know where the block ends. The forms that don't require a begin/end have a closing structure that tells the compiler where it ends and thus the begin/end would simply be redundant. You're free to use it in this case if you want, though.

Loren Pechtel
  • 8,945
  • 3
  • 33
  • 45
8

Niklaus Wirth (the designer of Pascal) corrected these inconsistences in his next language, Modula-2. In Modula-2, compound statements like IF have no BEGIN and a mandatory END:

IF {condition} THEN
    {statement-list}
END;

Other control structures such as WHILE are similar and consistent with REPEAT.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 3
    I wish he went the other way, and required 'begin' for all multi-statement blocks - just my preference. At least it's consistent in Modula-2. – 70Mike Jan 07 '11 at 00:09
  • 4
    @70Mike: It has to do with parsing theory. "Begin" is only needed if ambiguity exists as to whether the next node on the syntax tree will be a single statement or a block, the way it is in Pascal. (And in the C family; except there they use curly braces instead of keywords. Same principle, though.) The **begin** is a keyword that lets the parser know to expect a block. When you disallow single statements by making everything a block that has to end in an **end**, then there's no need for a **begin** to tell the parser there's a block coming up. – Mason Wheeler Jan 07 '11 at 01:06
  • 1
    IIRC the prefered loop statement in Modula-2 is LOOP..END; WHILE and REPEAT are just special cases of LOOP (with the check+EXIT at resp the beginning or the end – Marco van de Voort Mar 11 '11 at 08:31
5

The question is: Wouldn't it be better ?

The answer is: That depends, as this sort of thing is entirely subjective. Unless you are, or think like, a machine.

Yes, it would satisfy some ache for consistency to enforce begin/end for ALL compound statements, but where the surrounding language elements already provide a natural enclosure, it is utterly redundant to require this.

Consider the CASE statement:

// "Sensible" syntax

  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;
  else
    DoForAllOtherValues;
    DoMore;
  end;

Versus a less sensible but more consistent and "logical":

  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;
  else
    begin
      DoForAllOtherValues;
      DoMore;
    end;
  end;

Notice that the final "end" is part of the "case". You cannot do without it.

I am fairly sure that in an early version of Chrome (that became Oxygene and subsequently Prism) this was actually required syntax for the case statement. If so, it is no longer the case. Common sense presumably prevailed.

In my personal opinion, satisfying the OGoSC (Objective Gods of Syntactic Consistency) angers the perhaps lesser, but actually more relevant to you and me, SGoHRaC (Subjective Gods of Human Readability and Comprehension).

Though in many cases it might appear otherwise, we humans are not in fact machines. We do not need to simplify and reduce rules to a minimum consistent set to make it possible to parse text and make sense of it. We need some rules, but we can handle more, since our great advantage over machines is a freedom of thought that liberates us from a strict regimen of syntax and structure, especially where such syntax and structure is extraneous to the point of redundancy.

As in this case.

If you make a mistake that the compiler cannot interpret, it will tell you, every time you compile. But the compiler won't thank you for making the code "easier" to "read" (the compiler simply follows the rules it is given - it does not make it "easier" for the compiler to "read" the code by changing the rules that it can already follow perfectly happily).

If you impose arbitrary rules that make it harder to read (not because the rules are more or less invariant/consistent, but because you impose a consistent structure that itself contains more noise and redundant information that has to be filtered) then you will pay the price in human productivity.

In fact, these "easier" more "consistent" rules, may actually may make it harder all around ... consider again the CASE statement.

To make that compound begin/end make sense, we must make "case" a standalone statement, not part of a case/end pair, thus ALL of these should be valid syntax:

  case VALUE of
    1: DoSomething;
    2: DoSomethingElse;


  case VALUE of
    1: DoSomething;
    2: DoSomethingElse;
  else
    DoOther;


  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;
  else
    DoOther;


  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;
  else
  begin
    DoOther;
    DoMoreOther;
  end;


  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;

You may disagree, but it seems to me that suddenly this more consistent syntax results actually in LESS consistency in the actual code, even though there is greater consistency in the rules that the code is being written to conform to.

Deltics
  • 22,162
  • 2
  • 42
  • 70
  • 1
    Answers the question at the end of my post - "Wouldn't it be better...?" but not the title of the question - "Why are ...?". It's an excellent answer to the followup question, which I should have asked separately. My fault. – 70Mike Jan 07 '11 at 01:01
  • 1
    It does answer the why: They appear to be inconsistent because they are designed to be easily read by a human, not mechanically parsed by a machine. – Deltics Jan 07 '11 at 02:08
  • You are mistaken - the Pascal language proper does NOT have an `else` part in `switch` statement, see here http://books.google.com/books?id=GBISkhhrHh8C&lpg=PA254&ots=Gh_e8WcsMu&pg=PA254 . Whatever implementation added that else extension made it in grossly inconsistent way of how `else` works in Pascal. I have seen other implementations that added `otherwise:` clause with normal for case `:` rules – Nas Banov Feb 03 '11 at 23:22
  • Nas - I am not mistaken in stating that the Delphi variant of the Pascal language has an "else" clause in the CASE statement (where-as you are on the otherhand mistaken for calling it "switch" ;)). I see no point discussing the strictly "original" Pascal language spec when it is the Delphi derivation that is of relevance to the question. And don't see how or why you consider "else" to be grossly inconsistent in a CASE - it appears perfectly consistent with it's use in an if/else if/else if/else usage. "otherwise" on the otherhand is inconsistent, being uniquely used in CASE. – Deltics Feb 04 '11 at 01:58
  • @Deltics - do you have to use `:` after `else` in `if`? can you have more than 1 statement in `else` of an `if`, like you can in `case`? ;-) You see, the resemblance between the `else` and `else:` is only superficial – Nas Banov Feb 10 '11 at 09:03
  • @Deltics: See here what the generic name of Pascal's `case` is: http://en.wikipedia.org/wiki/Switch_statement – Nas Banov Feb 10 '11 at 09:08
  • @Nas - see here what is RELEVANT to this question: D.E.L.P.H.I, or if you want to be precise, ObjectPascal. We are not talking about a theoretical or academic "standard" version of Pascal but a specific dialect. As for consistency, that goes beyond (or not as far as, depending on your p.o.v) attendant symbols related to a keywords usage imho. – Deltics Feb 10 '11 at 20:03
3

Probably. But language design, especially languages with a bit of history, is rarely straightforward or ideal.

You can see similar things in other languages. Java, for example, requires a block after try and won't allow a single statement, although a single statement might also work if you just look at other control structures.

Why is switch in C and derived languages a single block and the individual cases not?

Joey
  • 344,408
  • 85
  • 689
  • 683
  • I'm suspecting there's something to do with "until' in the repeat...until structure acting as a statement-list terminator, and 'except' doing the same for try-except. That makes sense but I wonder if there's any better reason for not staying consistent to the more formal begin...end block structure. – 70Mike Jan 07 '11 at 00:07
  • Interestingly, I never noticed it as a problem (contrary to the other examples I cited). – Joey Jan 07 '11 at 00:08
  • I'm noticing it because I'm planning a utility to format Delphi source code. I've tried a couple but haven't found one that can cope with a workmate's pathological coding style yet. – 70Mike Jan 07 '11 at 00:14
2

It has to do with the way the parser works. Begin/end, try/except and repeat/until all contain blocks of statements. The parser's code looks something like this, for a begin block (pseudocode):

procedure ReadBlock;
begin
  Match('begin');
  while CurrentToken <> 'end' do
    ReadStatement;
  Match('end');
end;

And that works fine for that type of block. But when you need additional information in the block ending line (a conditional for the repeat/until, and an exception-handling block for the try,) then you don't want it to run until end, which the language's grammar expects to not have anything after it. You could modify the grammar, but that would add a lot of complexity to the parser. So instead you just pick a different keyword.

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
1

I guess you are asking the wrong question. I mean, may be you are not seeing the difference between the if/while/for group and the repeat/try group.

The first group needs something (condition or arguments) to BEGIN something. The second, instead, implies to BEGIN something. Just read the words: repeat (the following) and try (the following).

Pascal is clean, simple and elegant because it's designed for regular human readers, Professor Wirth had in mind people learning programming when he designed it.

someone
  • 916
  • 1
  • 5
  • 8
  • I don't see the implied difference here. repeat (the following) may mean just repeat one statement, not a list of statements. 'while (condition) do ...' seems the same as 'repeat ... until (condition)' except that it's test-first instead of test-last, not because it implies a bunch of actions instead of a single one. – 70Mike Jan 07 '11 at 01:19
  • Neither did Wirth, since he replace while and repeat by a single LOOP in successor language modula2. Still, it reeks of language hobbyism. Syntax details really don't matter THAT much. – Marco van de Voort Mar 02 '16 at 11:08
1

You are partly correct - on the repeat <stmts> until <expr> statement.

It feels a bit of a cheat that you don't need BEGIN-END for compound statement consistency but this is to avoid undue suffering. Because you see in all other cases you need the begin-end bracketing effect to show where the part of the code to which then or else or loops do apply to. REPEAT-UNTIL is the only Pascal statement i can think of that necessitates a far-removed second part - because it makes sense the condition for loop exit to be textually where it will be checked - after the loop body. An alternative form could have been

UNTIL <condition> DO <statement>

UNTIL <condition> DO
  BEGIN
    <statements>
  END

but then it would be way too confusing to explain and persuade the language users that the condition will be checked only after the block is executed at least once. So it's a good thing Wirth did not do it this way.

In regards to try <stmts> except <stmts> end - this is not from the original Pascal language design and specification, this has been slapped in as after-thought by some implementor (Borland? FreePascal?), so it's no wonder it is inconsistent - the thought has been more to the lines of "can i do it without breaking existing programs" than overall specification design. Another example of language extension was given in answer above - the default clause else in the case switch - and while i find this very useful and had used it back in the days in Turbo Pascal - this is horribly inconsistent with the use of else in the if construct. Thus i find another implementation i have seen and used better - otherwise: followed by a single statement as in each <value>: case.

Nas Banov
  • 28,347
  • 6
  • 48
  • 67