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