Guess the output of this program.

Guess the output of this program.

Is this three Delphi bugs for the price of one?

Compiler mentions: 

[dcc32 Hint] WeirdCaseConstruct.dpr(11): H2077 Value assigned to ‘Handled’ never used

1. If statement inside case – after ELSE option?

2. Handled is actually used

3. else Test(4) is never called

 XE7.1 (32-bit, Windows)

program WeirdCaseConstruct;

{$APPTYPE CONSOLE}

{$R *.res}

uses

  System.SysUtils;

procedure Test(const Value: Integer);

var

  Handled: Boolean;

begin

  Handled := True; // <- Hinted

  case Value of

    1: writeln(‘One’);

    2: writeln(‘Two’);

    else Handled := False;

    if not Handled

     then Writeln(Value, ‘ is unhandled’)

      else Test(4);

  end;

end;

begin

  Test(1);

  Test(3);

  Write(‘Press Enter’);

  Readln;

end.

31 thoughts on “Guess the output of this program.”

  1. I had to format it to differently to know what it will do:

    procedure Test(const Value: Integer);

    var

     Handled: Boolean;

    begin

     Handled := True;

     case Value of

      1: writeln(‘One’);

      2: writeln(‘Two’);

     else

      Handled := False;

      if not Handled then

       writeln(Value, ‘ is unhandled’)

      else

       Test(4);

     end;

    end;

    Output should be:

    One

    3 is unhandled

    Press Enter

    PS.

    I don’t see a bug.

  2. Let me reformat and re-emphasize the weirdness…

    How can the statement in italics be valid inside a case statement?

    program WeirdCaseConstruct;

    {$APPTYPE CONSOLE}

    {$R *.res}

    uses

      System.SysUtils;

    procedure Test(const Value: Integer);

    var

      Handled: Boolean;

    begin

      Handled := True; // <- Hinted

      case Value of

        1: writeln(‘One’);

        2: writeln(‘Two’);

        else begin

          Handled := False;

        end;

       

      if not Handled

         _then Writeln(Value, ‘ is unhandled’)_

          else Test(4);

      end;

    end;

    begin

      Test(1);

      Test(3);

      Write(‘Press Enter’);

      Readln;

    end.

  3. After a refresh I’ve seen that you updated your question:

    The Value “True” that is assigned to Handled is never used. This is correct. (Its the value, not the variable!)

  4. The code as it should have been written…

    No hint, else works.

    program WeirdCaseConstruct;

    {$APPTYPE CONSOLE}

    {$R *.res}

    uses

      System.SysUtils;

    procedure Test(const Value: Integer);

    var

      Handled: Boolean;

    begin

      Handled := True;

      case Value of

        1: writeln(‘One’);

        2: writeln(‘Two’);

        else begin

          Handled := False;

        end;

      end;

      if not Handled // <- Outside case

         then Writeln(Value, ‘ is unhandled’)

          else Test(4);

    end;

    begin

      Test(1);

      Test(3);

      Write(‘Press Enter’);

      Readln;

    end.

  5. Lars Fosdal Like I said, there is an implicit begin end block for the “else” in a case statement.

    It’s different from it then else …

    That’s the way it is.

  6. Your program is equivalent to this one:

    {$APPTYPE CONSOLE}

    procedure Test(const Value: Integer);

    var

      Handled: Boolean;

    begin

      Handled := True; // <- Hinted

      case Value of

        1:

          writeln(‘One’);

        2:

          writeln(‘Two’);

      else

        begin

          Handled := False;

          if not Handled then

            writeln(Value, ‘ is unhandled’)

          else

            Test(4);

        end;

      end;

    end;

    begin

      Test(1);

      Test(3);

      Write(‘Press Enter’);

      Readln;

    end.

  7. If you’d asked this on SO, then we could have produced a nice Q&A that would have been curated for anybody else in the future who comes across this issue. As it stands, the value here will be lost.

  8. I guess it just goes to show that you should really mind the hints in your code, not only the warnings.  Perhaps a warning about code being eliminated would be more appropriate in this case.

  9. The block nature of the else clause was evident in the TP 1.0 manual. No exposition was given to the topic, but the example in the manual had two lines of code in the else block. And as the code was well formatted, the intention was apparent.

  10. Lars Fosdal  Why be appalled. Where is the ambiguity? There is none. The real problem is the whole single/compound statement. It was “fixed” in Modula-2. Too late for us though.

  11. Asbjørn Heid – My error was to assume that the else in case, behaved like else in if.  The other ones you mention are block defining in their own right.  I never was aware that the case else behaved that way.  Now, I feel silly – and annoyed.

  12. Lars Fosdal they are few exceptions for the usage of begin/end to declare a block of instructions: “repeat … until”, “try … except…end”, “try ..finally…end”, and the “case  else … end”.

  13. Lars Fosdal Even in try except end one can have an else without a begin/end and it behaves just like the case statement. 😉

    try

    except

      on E: EOSError do

        Writeln(E.Message);

    else

      Write(‘Exception’);

      Writeln(‘ unknown’);

    end;

  14. Martin Wienold – good point.

    Wonder why they didn’t opt for

    try

    exception E of

      EOSError: …;

      else

    end;

    Bill Meyer – Clearly, a head case. 

  15. Cool. I’ve always been overly verbose in except on, and especially repeat (a syntactically begin-end-eye-opener). Never thought about the case else the same way.

    It’s the same thing apparently. I do not think anyone would mind (except when sitting on loads of legacy code) if begin-end was enforced in these cases.

Leave a Reply