Unsure tabbing with Pascal [closed]

2019-09-20 19:29发布

问题:

Hi I'm trying to tab some code, please could someone check to make sure I have done this correctly (Changed some code for simplicity):

begin
  if Password <> Database['Database']
    then showmessage ('Message')
    else
  if NewPassword <> Retype
    then showmessage ('Message')
    else
      begin
        if Message (yes, No, etc) =yes
          then
            begin
              List
              List
              List.post;
              showmessage ('Message')
            end
          else close;
      end;
end;

回答1:

This is a coding style question, and may not survive here very long. :-) (Coding style is very much a matter of personal opinion, and there are an awful lot of different ones out there.) I'll give it a shot, anyway. :-)

I'd do it slightly differently. IMO, this clearly shows the proper pairings of if..else and begin..end to a new programmer:

begin
  if Password <> Database['Database'] then
    showmessage ('Message')
  else 
    if NewPassword <> Retype then
      showmessage ('Message')
    else
    begin
      if Message (yes, No, etc) = yes then
      begin
        List;
        List;
        List.post;
        showmessage ('Message');
      end
      else
        close;
    end;
end;

In my own code, I'd do it a little differently still (but only a minor difference). I'd move the else if password to the same line (it reduces one level of indent, and to me makes the flow of the code more clear. We have three possible options, and there are three options clearly shown (if this, else if this, else this):

begin
  if Password <> Database['Database'] then    // option 1
    showmessage ('Message')
  else if NewPassword <> Retype then          // option 2
    showmessage ('Message')
  else                                        // option 3
  begin
    if Message (yes, No, etc) = yes then
    begin
      List;
      List;
      List.post;
      showmessage ('Message');
    end
    else
      close;
  end;
end;

There are only a couple of other code areas where formatting sometimes makes a difference. I'll try to quickly touch as many of them as I can think of off-hand.

Case statements:

case i of
  0: DoThingForZero;            // Only one line to execute for 0
  1: begin                      // Two things to do for 1
       DoSetupForOne;
       DoThingForOne;
     end;
  2: DoThingForTwo;
else                            // Handle anything other than 0, 1, 2
  DoThingsForOtherValues;
end;

While statements:

while not Query1.Eof do
begin
  // Process each field in current record of table
  Query1.Next;  // Move to next row (easy to forget, infinite loop happens. :-)
end;

Repeat statements:

i := 1;
repeat
  i := i + SomeFunctionResultReturningVariousValues();
until (i >  50)

For loops:

for i := 0 to List.Count - 1 do
begin
  ProcessItem(List[i]);
end;

for i := List.Count - 1 downto 0 do
  List[i].Delete;

For..in loops:

for ch in SomeString do           // For each character in a string,
  WriteLn(ch, ' = ', Ord(ch));    // write the ordinal (numeric) value 
ReadLn;

Try..finally:

SL := TStringList.Create;        // Create object/open file/whatever (resource)
try
  // Code using resource 
finally
  SL.Free;                       // Free the resource
end;

Try..except:

try
  // Do something that might raise an exception
except
  on E: ESomeVerySpecificException do
  begin
     // Handle very specific exception 
  end;
  on E: ESomeLessSpecificException do
  begin
    // Handle less specific exception
  end;
  else
    raise;
end;

Try..finally with try..except:

SL := TStringList.Create;         // Allocate resource
try
  try
    // Do something that might raise exception
  except
    // Handle exception as above
  end;
finally
  SL.Free;                       // Free resource
end;


回答2:

Here's how I would format that code:

begin
  if Password <> Database['Database'] then
    showmessage ('Message')
  else
  if NewPassword <> Retype then
    showmessage ('Message')
  else
  begin
    if Message (yes, No, etc) =yes then
    begin
      List
      List
      List.post;
      showmessage ('Message')
    end
    else
      close;
  end;
end;

The main differences are:

  • Keeping the then at the end of the same line that if is on (unless there are multiple conditionals).
  • Keeping else statements in line with if statements


回答3:

Personally, I'm an else if guy and also I'm against hanging then:

procedure outer;
begin {outer's}
    if 2 * 2 = 4 then
    begin {this belongs to if...then level}
        Writeln('make bools');
    end
    else if Sin(X) = 3 then
    begin {and this too}
        Writeln('not war');
    end;
    else if True and SoOn then
        {...}
end; {/outer's}

But in your case I'd better avoid large compound statements and heavy nesting in else branch:

begin
    if not CurrentPasswordIsCorrect then
    begin
        Notify('bad pass');
        Exit;
     end;

     if NewPasswordEntry1 <> NewPasswordEntry2 then
     begin
        Notify('you forgot your password already');
        Exit;
     end;

     { and so on }
end;

Sometimes the rule about writing normal flow code to then branch and abnormal to else branch becomes a false friend and inviting writing a lot of nested statements to else which in turn only hurts readability instead of improving it.



回答4:

As noted in the other answers, style is highly subjective, and for that reason it is difficult to give an objective answer. However, something that can be said is how your code should look according to Embarcadero's Object Pascal Style Guide, and that is what I will attempt to answer (with some more detail than you asked for). When the same issue occurs in multiple locations, I will only mention it once.

begin
  if Password <> Database['Database']
    then showmessage ('Message')

Here, the casing of showmessage should be ShowMessage, which is also the name given to the procedure in the Dialogs unit. There should not be a space between ShowMessage and (.

Your use of then on the next line is unusual but okay, and you're right to indent it in that case.

    else
  if NewPassword <> Retype

This second if statement is part of the else branch of the first if statement, and should be indented accordingly, possibly by placing it on the same line as the else.

    then showmessage ('Message')
    else
      begin

begin and end should not have extra indentation: the substatements should be two spaces to the right of the else above.

        if Message (yes, No, etc) =yes

The fact that you have a space before the =, but not one after it, is not something I've seen before, but this is not a situation where the style guide expresses any preference, so that is okay.

          then
            begin
              List
              List
              List.post;
              showmessage ('Message')
            end
          else close;

This deserves an extra mention: else followed by a statement is explicitly called out as having fallen out of favour, but nonetheless okay, in the style guide.

      end;
end;

Something else worth mentioning is that your use of two spaces for indentation is exactly what the style guide says to use.