delphidelphi-10.3-rio

DELPHI - Extra semi-colons in except blocks, any purpose? Optional semi-colon before except or end, What's better with or without?


Working in a Delphi 10.3.3 application with a ton of extra & missing semi-colons. The app compiles if they are dropped prior to any block ending statement.

Does a floating semi-colon between [except] and [end] serve any purpose in the code, such as faster run time or throw some default exception, or some other purpose?

Could this throw a random compile or runtime error?

Does leaving a semi-colon off the last line before an end or except speed up runtime?

Is one way, more error-prone than another or subject to random compile or runtime errors?

Here is code that can be dropped into any test project with a form having an edit box, a button and a memo box created with drag-n-drop default settings.

function TForm1.isThisUseful(this : string): boolean;
var
  i: Integer;
begin
  result := false;
  try
    if this = ''
    then
      i := 0
    else
      i := 1
  except
    ;
  end;
  result := (i > 0)
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if isThisUseful(Edit1.Text)
  then
    Memo1.Text := 'Yes, it is useful'
  else
    Memo1.Text := 'This is a waste of time.'
end;

Solution

  • I thought I would try some measurements, using the Line Timer of NexusDB's Quality Suite on this D7 test program:

    {$A8,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N+,O-,P+,Q-,R-,S-,T-,U-,V+,W+,X+,Y+,Z1}
    program semicolontest;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils;
    
    function isThisUseful1(this : string): boolean;
    var
      i: Integer;
    begin
      result := false;
      try
        if this = ''
        then
          i := 0
        else
          i := 1
      except
        ;
      end;
      result := (i > 0)
    end;
    
    function isThisUseful2(this : string): boolean;
    var
      i: Integer;
    begin
      result := false;
      try
        if this = ''
        then
          i := 0
        else
          i := 1
      except
    
      end;
      result := (i > 0)
    end;
    
    var
      Input : String[20];
      i : Integer;
      Res : Boolean;
    
    begin
    
       Input := 'abcdefg';
    
       writeln('Starting');
       for i := 1 to 1000000 do begin
         Res := isThisUseful1(Input);
         Res := isThisUseful2(Input);
       end;
       writeln('Done');
       // readln;
    end.
    

    which contains two versions of the isThisUseful function from the question, one with, and one without the semicolon in the except block. The results of running this code (with apologies for the slightly mangled layout) are as follows:

    Line    Total Time  Hit Count   Source
    1       -   {$A8,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N+,O-,P+,Q-,R-,S-,T-,U-,V+,W+,X+,Y+,Z1}
    2       -   program semicolontest;
    3       -   
    4       -   {$APPTYPE CONSOLE}
    5       -   
    6       -   uses
    7       -     SysUtils;
    8       -   
    9       -   function isThisUseful1(this : string): boolean;
    10      -   var
    11      -     i: Integer;
    12  2.807175    1,000,000   begin
    13  0.761388    1,000,000     result := false;
    14  2.133202    1,000,000     try
    15  1.403061    1,000,000       if this = ''
    16      -       then
    17      -         i := 0
    18      -       else
    19  0.826841    1,000,000         i := 1
    20      -     except
    21      -       ;
    22      -     end;
    23  0.735419    1,000,000     result := (i > 0)
    24      -   end;
    25      -   
    26      -   function isThisUseful2(this : string): boolean;
    27      -   var
    28      -     i: Integer;
    29  1.260030    1,000,000   begin
    30  0.782293    1,000,000     result := false;
    31  0.894420    1,000,000     try
    32  0.820860    1,000,000       if this = ''
    33      -       then
    34      -         i := 0
    35      -       else
    36  0.873424    1,000,000         i := 1
    37      -     except
    38      -   
    39      -     end;
    40  0.778922    1,000,000     result := (i > 0)
    41      -   end;
    42      -   
    43      -   var
    44      -     Input : String[20];
    45      -     i : Integer;
    46      -     Res : Boolean;
    47      -   
    48  1.167140    1   begin
    49      -   
    50  0.000036    1      Input := 'abcdefg';
    51      -   
    52  0.641347    1      writeln('Starting');
    53  0.000026    1      for i := 1 to 1000000 do begin
    54      -        Res := isThisUseful1(Input);
    55      -        Res := isThisUseful2(Input);
    56  0.669066    1,000,000      end;
    57  0.402661    1      writeln('Done');
    58      -      // readln;
    59      -   end.
    60      -   
    

    Notice that no time is recorded for line 21, the semicolon in the try ...except block, for the simple reason that, as expected, no code is generated for it.

    For completeness, the following are disassemblies of isThisUseful1 and isThisUseful2

    isThisUseful1:

    Address Bytes   Text    Block #
    00408620h       [semicolontest.dpr.12] begin    
    00408620h   55        push ebp  1
    00408621h   8BEC          mov ebp, esp  1
    00408623h   83C4F4        add esp, 0FFFFFFF4h ; (-0Ch)  1
    00408626h   53        push ebx  1
    00408627h   56        push esi  1
    00408628h   57        push edi  1
    00408629h   8945FC        mov [ebp-04h], eax    1
    0040862Ch   8B45FC        mov eax, [ebp-04h]    1
    0040862Fh   E87CB7FFFF        call System::LStrAddRef ;(00403DB0h)  1
    00408634h   33C0          xor eax, eax  1
    00408636h   55        push ebp  1
    00408637h   689A864000        push offset @@6   1
    0040863Ch   64FF30        push fs:[eax] 1
    0040863Fh   648920        mov fs:[eax], esp 1
    00408642h       [semicolontest.dpr.13] result := false; 
    00408642h   C645FB00          mov byte ptr [ebp-05h], 00h   1
    00408646h       [semicolontest.dpr.14] try  
    00408646h   33C0          xor eax, eax  1
    00408648h   55        push ebp  1
    00408649h   6872864000        push offset @@3   1
    0040864Eh   64FF30        push fs:[eax] 1
    00408651h   648920        mov fs:[eax], esp 1
    00408654h       [semicolontest.dpr.15] if this = '' 
    00408654h   837DFC00          cmp dword ptr [ebp-04h], 00h  1
    00408658h   7507          jnz @@1   1
    0040865Ah       [semicolontest.dpr.17] i := 0   
    0040865Ah   33C0          xor eax, eax  2
    0040865Ch   8945F4        mov [ebp-0Ch], eax    2
    0040865Fh   EB07          jmp @@2   2
    00408661h       [semicolontest.dpr.19] i := 1   
    00408661h       @@1:    
    00408661h   C745F401000000        mov dword ptr [ebp-0Ch], 01h  3
    00408668h       @@2:    
    00408668h   33C0          xor eax, eax  4
    0040866Ah   5A        pop edx   4
    0040866Bh   59        pop ecx   4
    0040866Ch   59        pop ecx   4
    0040866Dh   648910        mov fs:[eax], edx 4
    00408670h   EB0A          jmp @@4   4
    00408672h       @@3:    
    00408672h   E9DDACFFFF        jmp System::HandleAnyException ;(00403354h)   5
    00408677h       [semicolontest.dpr.21] ;    
    00408677h   E8B8AEFFFF        call System::DoneExcept ;(00403534h)  5
    0040867Ch       [semicolontest.dpr.23] result := (i > 0)    
    0040867Ch       @@4:    
    0040867Ch   837DF400          cmp dword ptr [ebp-0Ch], 00h  6
    00408680h   0F9F45FB          setnle [ebp-05h]  6
    00408684h   33C0          xor eax, eax  6
    00408686h   5A        pop edx   6
    00408687h   59        pop ecx   6
    00408688h   59        pop ecx   6
    00408689h   648910        mov fs:[eax], edx 6
    0040868Ch   68A1864000        push offset @@7   6
    00408691h       @@5:    
    00408691h   8D45FC        lea eax, [ebp-04h]    7
    00408694h   E8BFB3FFFF        call System::LStrClr ;(00403A58h) 7
    00408699h   C3        ret   7
    0040869Ah       @@6:    
    0040869Ah   E9E1ADFFFF        jmp System::HandleFinally ;(00403480h)    8
    0040869Fh   EBF0          jmp @@5   8
    004086A1h       @@7:    
    004086A1h   8A45FB        mov al, [ebp-05h] 9
    004086A4h       [semicolontest.dpr.24] end; 
    004086A4h   5F        pop edi   9
    004086A5h   5E        pop esi   9
    004086A6h   5B        pop ebx   9
    004086A7h   8BE5          mov esp, ebp  9
    004086A9h   5D        pop ebp   9
    004086AAh   C3        ret   9
    

    isThisUseful2:

    Address Bytes   Text    Block #
    00408620h       [semicolontest.dpr.12] begin    
    00408620h   55        push ebp  1
    00408621h   8BEC          mov ebp, esp  1
    00408623h   83C4F4        add esp, 0FFFFFFF4h ; (-0Ch)  1
    00408626h   53        push ebx  1
    00408627h   56        push esi  1
    00408628h   57        push edi  1
    00408629h   8945FC        mov [ebp-04h], eax    1
    0040862Ch   8B45FC        mov eax, [ebp-04h]    1
    0040862Fh   E87CB7FFFF        call System::LStrAddRef ;(00403DB0h)  1
    00408634h   33C0          xor eax, eax  1
    00408636h   55        push ebp  1
    00408637h   689A864000        push offset @@6   1
    0040863Ch   64FF30        push fs:[eax] 1
    0040863Fh   648920        mov fs:[eax], esp 1
    00408642h       [semicolontest.dpr.13] result := false; 
    00408642h   C645FB00          mov byte ptr [ebp-05h], 00h   1
    00408646h       [semicolontest.dpr.14] try  
    00408646h   33C0          xor eax, eax  1
    00408648h   55        push ebp  1
    00408649h   6872864000        push offset @@3   1
    0040864Eh   64FF30        push fs:[eax] 1
    00408651h   648920        mov fs:[eax], esp 1
    00408654h       [semicolontest.dpr.15] if this = '' 
    00408654h   837DFC00          cmp dword ptr [ebp-04h], 00h  1
    00408658h   7507          jnz @@1   1
    0040865Ah       [semicolontest.dpr.17] i := 0   
    0040865Ah   33C0          xor eax, eax  2
    0040865Ch   8945F4        mov [ebp-0Ch], eax    2
    0040865Fh   EB07          jmp @@2   2
    00408661h       [semicolontest.dpr.19] i := 1   
    00408661h       @@1:    
    00408661h   C745F401000000        mov dword ptr [ebp-0Ch], 01h  3
    00408668h       @@2:    
    00408668h   33C0          xor eax, eax  4
    0040866Ah   5A        pop edx   4
    0040866Bh   59        pop ecx   4
    0040866Ch   59        pop ecx   4
    0040866Dh   648910        mov fs:[eax], edx 4
    00408670h   EB0A          jmp @@4   4
    00408672h       @@3:    
    00408672h   E9DDACFFFF        jmp System::HandleAnyException ;(00403354h)   5
    00408677h       [semicolontest.dpr.21] ;    
    00408677h   E8B8AEFFFF        call System::DoneExcept ;(00403534h)  5
    0040867Ch       [semicolontest.dpr.23] result := (i > 0)    
    0040867Ch       @@4:    
    0040867Ch   837DF400          cmp dword ptr [ebp-0Ch], 00h  6
    00408680h   0F9F45FB          setnle [ebp-05h]  6
    00408684h   33C0          xor eax, eax  6
    00408686h   5A        pop edx   6
    00408687h   59        pop ecx   6
    00408688h   59        pop ecx   6
    00408689h   648910        mov fs:[eax], edx 6
    0040868Ch   68A1864000        push offset @@7   6
    00408691h       @@5:    
    00408691h   8D45FC        lea eax, [ebp-04h]    7
    00408694h   E8BFB3FFFF        call System::LStrClr ;(00403A58h) 7
    00408699h   C3        ret   7
    0040869Ah       @@6:    
    0040869Ah   E9E1ADFFFF        jmp System::HandleFinally ;(00403480h)    8
    0040869Fh   EBF0          jmp @@5   8
    004086A1h       @@7:    
    004086A1h   8A45FB        mov al, [ebp-05h] 9
    004086A4h       [semicolontest.dpr.24] end; 
    004086A4h   5F        pop edi   9
    004086A5h   5E        pop esi   9
    004086A6h   5B        pop ebx   9
    004086A7h   8BE5          mov esp, ebp  9
    004086A9h   5D        pop ebp   9
    004086AAh   C3        ret   9
    

    (I went cross-eyed trying to compare these myself, and wasn't going to waste my time running them past BeyondCompare).

    Anyway, I think this shows that as stated by myself and others, the compiler does not generate code for a line containing only a semicolon in a try...except block, and it shouldn't do anywhere else, either, though as noted there are cases where the presence or otherwise of a semicolon changes the semantics of the code and hence the code generated.