Thursday 22 December 2016

Reasons why I dislike dangling begins

Recently I've been writing a coding standards document and some Delphi developers seem to like the dangling begin format (Egyptian style) of begin/ends, here is an example of what this is:

function DoSomething: boolean;
begin
    Result := False;
    if FDone then begin
        Result := True;
    end;
end;

The 'begin' is at the end of the line rather than on a line of its own. I believe the original reason for this was to reduce the number of lines of code, this helped save paper when printing out code at schools and universities.

This format I personally cannot stand and cannot see a modern valid argument for doing this. I have not printed out code for years and think the argument that it saves some paper to be a very weak one compared to the improved readability of the 'begin' being in-line with the end.  

This is how I would write the function:

function DoSomething: boolean;
begin
    Result := False;
    if FDone then 
    begin
        Result := True;
    end;
end;

As you can see the 'begin' and 'end' are in-line and it is more readable. But why is it more readable? I have been trying to understand why I think it is more readable and here are some reasons:

  • The begin/end is in-line so the eye can naturally move vertically down to see the end of the code block. 
  • It matches the function and procedure begin/end pattern, therefore is more consistent. The begin/end of a function or procedure is usually in-line, although I have seen code where this is not the case.
  • The 'begin' is visually linked to the 'end', consider the Gestalt principle of proximity and continuity (see diagrams below).

The diagram above shows squares to represent the 'begin' and 'ends', the first group uses the dangling begins and the second puts the 'begin' on a new line making the 'begin' and 'ends' in-line. It seems easier to link the second group because they are in-line.




I have seen recently that Apple's Swift language uses the 'Egyptian' style,  for example:

func tableView(tableView: UITableView) -> Int {
   return 10
}

Using this format in Delphi the function would look like this:

function DoSomething: boolean; begin
    Result := false;
    if FDone then begin
        Result := true;
    end;
end;

This would make the begin/ends more consistent, however I like this even less.

It is a matter of personal preference, and I prefer the in-line begin/ends and in-line curly brackets in C#, I cannot see how I will ever change my opinion on this.   

15 comments:

  1. In a project where people using dangling begin/end I always ask why they don't do the "Egyptian" style like some people in C# / Swift other languages do.

    Usually then they revert to the style used in RTL/VCL

    ReplyDelete
  2. I totally disagree :-)
    You see your blocks of code as begin/end blocks, where you should see them as "if" blocks, or "for" blocks or "while" blocks and so on. The first line of the block defines its type. The structural code highlighters I use all give me perfect looking blocks of code.
    BTW, your code should look more like:
    Result := FALSE;
    if FDone then // No need for begin/end here
    Result := TRUE;

    Or maybe better :-p
    Result := FDone;

    ReplyDelete
    Replies
    1. Thanks for your comment. From what you say about the being seen as 'if' blocks, then why did they even have a 'begin', do you think that 'begin' should never have been introduced and ideally it should be removed completely?

      You raise another question regarding false, False or FALSE. I have corrected the code to match what the Delphi source files, why do you think it should be uppercase?

      You also raise another question regarding whether to always put a begin/end around every block and not allow 2 line 'if' statement.

      The function is not a real world function and I quickly wrote it to highlight the format.

      Delete
    2. If it was a real world function that existed in a piece of software, then yes you are right it should be 'Result := FDone;'. But if I saw that function in any code, the first thing I would point out is that you should never write a function called 'DoSomething'.

      Delete
    3. My code didn't "look" good because indentation was lost when publishing my comment. See Eric's comment below.
      About the capitalization of TRUE/FALSE: I don't remember where I got that from, but in my memory it is because TRUE and FALSE are defined as *constants* in Delphi, and constants usually are capitalized.

      Delete
    4. If your coding standards state that all constants are capitalized then yes you probably should capitalize TRUE and FALSE, you should also capitalize NIL.

      Delete
  3. I used to use dangling begins. Partly because it saved an extra line and is how I did it in C.

    After many years and inheriting/rehabilitating dozens of projects originally written by other developers, I have found that it does not improve readability and makes it easy to miss coding mistakes.

    Unless there is a really good reason to do otherwise, I try to use something similar to the Borland/Embarcadero standard. Being clever for the sake of being clever doesn't always help get the job done.

    ReplyDelete
  4. I prefer them on separate lines as you do, however personally speaking I hate coding standards.

    ReplyDelete
  5. I agree that dangling begins makes the code harder to read and that it is also contrary to the object pascal style guide which states "Never place a begin statement on the same line with any other code".

    Dangling begins also wreak havoc on structural highlighters.

    Code blocks are much easier to see when the left side is at the same indentation level even without a highlighter (although I personally use one).

    ReplyDelete
  6. Oh, but there is some really good reason to write code that way. When someone tells you: "That's how it should be done, because I like that way, period." LOL

    ReplyDelete
  7. The purpose of a coding standard or coding conventions is consistency, which is important if you have multiple developers or if you move back and forth between different code bases. It helps make the intent of the code immediately obvious.

    Fortunately, tedious things like formatting and spacing can be handled by the built-in code formatter.

    ReplyDelete
  8. I used to debug with printouts and rulers.

    Paper is cheaper than time - the extra lines lets you find mismatches in nesting FAST when everything lines up.

    Plus, it just reads so much easier.

    ReplyDelete
  9. The primary visual cue for blocks is the indentation, having an orphan "begin" alone on its own line just messes up with that visual cue, and is detrimental to readability: you have to read/recognize it, rather than just being able to rely on the indentation.

    Your diagrams link the begin and the end, but those are minor, secondary visual cues. The indentation is the key cue.

    Line count is not an issue, and probably never has been TBH, even in old code, the comment blocks decoration and ASCII art took more lines. If they were really worried about paper use, they would have cut down on those :)

    Having the "begin" moved to the primary visual path is counter-productive: it just introduces "visual noise" between the cause of the block (if/while/for/etc.) and the block, without bringing any information: it does neither clarify the cause of the block, nor the block.

    Hence, it's purely negative, you can only tolerate or like it through habituation and training, but training and habituation can lead people to accept pretty much any kinds of bad behaviors.

    The new year is soon, time to get rid of that bad behavior :)

    ReplyDelete
    Replies
    1. Well said, better than I could as English is not my native language.
      Yes indentation is what matters, and nesting a few begin/end blocks is just so much more readable when you use only one line for the begin declaration, be it a condition or a loop.

      Delete
  10. I agree wholeheartedly! The second figure in your post says it all.

    ReplyDelete