Recent

Author Topic: Formatting in FreePascal  (Read 2904 times)

rnfpc

  • Jr. Member
  • **
  • Posts: 91
Formatting in FreePascal
« on: July 22, 2019, 04:40:46 am »
One of the reasons for success of Python is its code formatting/indentation. I find that Pascal formatting, though very clear, can be further simplified to Python-type formatting.

Following is some code (which really has 3 statement blocks: with, if and else) with 2 types of formatting:

Traditional Pascal:
Code: Pascal  [Select]
  1. with TBarSeries(Result) do
  2.   begin
  3.     BarBrush.Color := AColor;
  4.     BarPen.Color := AColor;
  5.     BarWidthStyle := bwPercentMin;
  6.     if APlotType = ptBars then
  7.       begin
  8.         AxisIndexX := AChart.LeftAxis.Index;
  9.         AxisIndexY := AChart.BottomAxis.Index;
  10.       end
  11.     else
  12.       begin
  13.         AxisIndexX := AChart.BottomAxis.Index;
  14.         AxisIndexY := AChart.LeftAxis.Index;
  15.       end;
  16.   end;

Modified (python-like):
Code: Pascal  [Select]
  1. with TBarSeries(Result) do begin
  2.   BarBrush.Color := AColor;
  3.   BarPen.Color := AColor;
  4.   BarWidthStyle := bwPercentMin;
  5.   if APlotType = ptBars then begin
  6.     AxisIndexX := AChart.LeftAxis.Index;
  7.     AxisIndexY := AChart.BottomAxis.Index;
  8.     end
  9.   else begin
  10.     AxisIndexX := AChart.BottomAxis.Index;
  11.     AxisIndexY := AChart.LeftAxis.Index;
  12.     end;
  13.   end;

The modified version results in less lines (separate line for begin is avoided) and less indentation (indentation for begin and end are avoided) so that 3 statement blocks are seen clearly.

I am interested in views of other users on this forum.
« Last Edit: July 22, 2019, 04:46:57 am by rnfpc »

440bx

  • Hero Member
  • *****
  • Posts: 1055
Re: Formatting in FreePascal
« Reply #1 on: July 22, 2019, 05:33:26 am »
One of the reasons for success of Python is its code formatting/indentation.
You may be right but, personally, I doubt it.

I find that Pascal formatting, though very clear, can be further simplified to Python-type formatting.
When I find code formatted in the "python way" you suggested, the first thing I do is reformat it to make its logical blocks more evident.

I'd format the snippet of code you presented as follows:
Code: Pascal  [Select]
  1. with TBarSeries(Result) do
  2. begin
  3.   BarBrush.Color := AColor;
  4.   BarPen.Color   := AColor;
  5.   BarWidthStyle  := bwPercentMin;
  6.  
  7.   if APlotType = ptBars then
  8.   begin
  9.     AxisIndexX := AChart.LeftAxis.Index;
  10.     AxisIndexY := AChart.BottomAxis.Index;
  11.   end
  12.   else
  13.   begin
  14.     AxisIndexX := AChart.BottomAxis.Index;
  15.     AxisIndexY := AChart.LeftAxis.Index;
  16.   end;
  17. end;
A begin/end denotes a compound statement that is controlled by its "owner" (in your example, the "with" and the "ifs".) Since compound statements are surrogates to their owner, they (IMO) should be at the same level of indentation since they are logically at the same level.


The modified version results in less lines (separate line for begin is avoided) and less indentation (indentation for begin and end are avoided) so that 3 statement blocks are seen clearly.
A separate line for "begin", not only should _not_ be avoided, it should be required because it marks the beginning of a block which should be aligned with the keyword that marks its end (in this case "end".)

One of the things I find most annoying in C code are "definitions" that go like this:
Code: C  [Select]
  1. struct astruct {
  2.   SOMETYPE somefieldname;
  3.   int someotherfieldname;
  4. }
For trivial definitions it's easy to "see" that it's one block but, when the data type has many other structured types in it, matching the "{" to the "}" is a pain, particularly when you have to add a new struct or field somewhere in there.  Another thing that makes the entire thing look like a blob of text is the total lack of alignment of types and variable/field names.  A large and complex structure defined like that is "binary roadkill".  Fortunately, most C programmers figured out that indenting the definitions a couple of spaces makes it easier to read.  In a few centuries, evolution willing, they might start  formatting code halfway decently.  Evolution is really a great thing, too bad it's so slow.

I am interested in views of other users on this forum.
Good indentation can make a program much easier to read and understand.
using FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

eric

  • Sr. Member
  • ****
  • Posts: 268
Re: Formatting in FreePascal
« Reply #2 on: July 22, 2019, 07:56:21 am »
I'm totally with 440bx on this. That's exactly how I do it. Indenting each end to the same level as its corresponding begin makes the structure beautifully clear, and helps to avoid some awkward bugs.

PascalDragon

  • Hero Member
  • *****
  • Posts: 512
  • Compiler Developer
Re: Formatting in FreePascal
« Reply #3 on: July 22, 2019, 09:05:03 am »
One of the reasons for success of Python is its code formatting/indentation. I find that Pascal formatting, though very clear, can be further simplified to Python-type formatting.
Python requires proper formatting as there it is part of the syntax. In other languages and especially Pascal this is not the case as everyone can choose their own style. Thus "measuring" the success of Pascal on that is nonsense.

By the way, when not working on the compiler, this is how I format my code:
Code: Pascal  [Select]
  1. with TBarSeries(Result) do begin
  2.   BarBrush.Color := AColor;
  3.   BarPen.Color := AColor;
  4.   BarWidthStyle := bwPercentMin;
  5.   if APlotType = ptBars then begin
  6.     AxisIndexX := AChart.LeftAxis.Index;
  7.     AxisIndexY := AChart.BottomAxis.Index;
  8.   end else begin
  9.     AxisIndexX := AChart.BottomAxis.Index;
  10.     AxisIndexY := AChart.LeftAxis.Index;
  11.   end;
  12. end;

440bx

  • Hero Member
  • *****
  • Posts: 1055
Re: Formatting in FreePascal
« Reply #4 on: July 22, 2019, 09:21:23 am »
By the way, when not working on the compiler, this is how I format my code:
Code: Pascal  [Select]
  1. with TBarSeries(Result) do begin
  2.   <snip>
  3.   if APlotType = ptBars then begin
  4.     AxisIndexX := AChart.LeftAxis.Index;
  5.     AxisIndexY := AChart.BottomAxis.Index;
  6.   end else begin
  7.     AxisIndexX := AChart.BottomAxis.Index;
  8.     AxisIndexY := AChart.LeftAxis.Index;
  9.   end;
  10. end;
The problem with that formatting is that it shows an "if" terminated with two "end"(s).  If statements are not terminated with "end"(s).
using FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

rnfpc

  • Jr. Member
  • **
  • Posts: 91
Re: Formatting in FreePascal
« Reply #5 on: July 22, 2019, 09:41:03 am »
@PascalDragon : you are 50% with Python-type formatting!

If you indent 'end's (and start 'else' on a new line with de-indentation), you will be 100%.
« Last Edit: July 22, 2019, 09:45:24 am by rnfpc »

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7302
Re: Formatting in FreePascal
« Reply #6 on: July 22, 2019, 09:50:24 am »

The modified version results in less lines (separate line for begin is avoided) and less indentation (indentation for begin and end are avoided) so that 3 statement blocks are seen clearly.

I am interested in views of other users on this forum.

The core meaning of indentation is readability, not to get is as short as possible (then put everything on one line with a space between it).

This way, to scan structure validity you have to constantly move your eyes from left to right to catch all those begins.  Pascal isn't a tennis game.

Moreover while a known alternative, it is the minority position, and going against majority rules is generally a bad thing anyway.

kupferstecher

  • Sr. Member
  • ****
  • Posts: 287
Re: Formatting in FreePascal
« Reply #7 on: July 22, 2019, 10:19:13 am »
This way, to scan structure validity you have to constantly move your eyes from left to right to catch all those begins.  Pascal isn't a tennis game.
The visual braces are build by "if [...]" and "end". You can see it from the indentation, that its a block. So there has to be a begin in the end of the line, no need to search for it.

Quote
Moreover while a known alternative, it is the minority position, and going against majority rules is generally a bad thing anyway.
Thats true. Especially if you work on more than one codebase.

I do an other custom formatting in special cases:
Outer loops/ifs I sometimes write in capital letters to make them more outstanding and thus more readable.

Code: Pascal  [Select]
  1. begin
  2.   [...]
  3.  
  4.   WHILE NOT Terminated DO BEGIN
  5.  
  6.     if not self.Enabled then BREAK;
  7.  
  8.     If SomeValue >= 0 Then Begin
  9.       lastItem:= 0;
  10.       for aitem in SomeArray do begin
  11.         aItem:= lastItem + aItem * SomeValue;
  12.         lastItem:= aItem;
  13.       end;//do      
  14.  
  15.     End Else Begin
  16.      for aitem in SomeArray
  17.      do aItem:= aItem * SomeValue;
  18.  
  19.     End;//If
  20.  
  21.     [...]
  22.  
  23.   END;//DO
  24.  
  25.  
  26. end;
« Last Edit: July 22, 2019, 10:29:00 am by kupferstecher »

dbannon

  • Hero Member
  • *****
  • Posts: 600
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Formatting in FreePascal
« Reply #8 on: July 22, 2019, 10:20:50 am »
@PascalDragon : you are 50% with Python-type formatting!

"Python -type"  ?   I was writing pascal code formatted like PascalDragon just showed us before Python was invented.

I still do, saving a few lines increases my chance of seeing a complete function on screen. I believe that is the key to readability.

Davo

Lazarus 1.8, Linux (and reluctantly Win10, OSX)
My Project - https://github.com/tomboy-notes/tomboy-ng

BrunoK

  • Full Member
  • ***
  • Posts: 158
  • Retired programmer
Re: Formatting in FreePascal
« Reply #9 on: July 22, 2019, 10:25:38 am »
My parameters for Jedi Code Formatter give this result, it looks quite like python and I have used that when programming in Quick Basic Compiled in the 80's and then in Delphi / Lazarus+FPC since the end of the 90's. And also in small teams in COBOL earlier.
Actually when I work on some parts of FPC, the first thing I do, if it is not something approaching  PascalDragon's style, is to do a big JCF run on the concerned unit or some of the parts I want to work on or understand.
Code: Pascal  [Select]
  1.   with TBarSeries(Result) do begin
  2.     BarBrush.Color := AColor;
  3.     BarPen.Color := AColor;
  4.     BarWidthStyle := bwPercentMin;
  5.     if APlotType = ptBars then begin
  6.       AxisIndexX := AChart.LeftAxis.Index;
  7.       AxisIndexY := AChart.BottomAxis.Index;
  8.     end
  9.     else begin
  10.       AxisIndexX := AChart.BottomAxis.Index;
  11.       AxisIndexY := AChart.LeftAxis.Index;
  12.     end;
  13.   end;
  14.  
or  kupferstecher example
Code: Pascal  [Select]
  1.     while not Terminated do begin
  2.       if not self.Enabled then
  3.         BREAK;
  4.       if SomeValue >= 0 then begin
  5.         lastItem := 0;
  6.         for aitem in SomeArray do begin
  7.           aItem := lastItem + aItem * SomeValue;
  8.           lastItem := aItem;
  9.         end;//do
  10.       end
  11.       else begin
  12.         for aitem in SomeArray do aItem := aItem * SomeValue;
  13.       end;//If
  14.       // [...]
  15.     end;//DO
  16.  
One of the most unreadable unit is \rtl\inc\objpas.inc with strange indent and spurious empty lines, others use a 1 character indent, these are awful and spells much doubt on the FPC developer comprehension of its code, I wont cite name ...
Lazarus is in general reasonably OK except for one package that is buggy and untestable/not understandable due to 1 character indent.

My preference is for indents to be at least as wide as one line height or an even multiple of that, problem occasionally appeearing in multiline bits of code (complicated if's, cstring concatenation, long formulas).
The python like formatting is not very good because the end is indented like the boby of the condition so it is difficult, visually to understand where the IF or WITH statements end.
Lazarus trunk r. 59978/03.01.2019 (+/- patches regarding enabled, TScrollBar, TCursorImage). FPC 3.0.4 32 bits. (+heaptrc with leaked ClassName+Revisited TList) , Windows 10 Pro x64 (v. 1803)

rnfpc

  • Jr. Member
  • **
  • Posts: 91
Re: Formatting in FreePascal
« Reply #10 on: July 22, 2019, 10:37:41 am »
We often have to use "//do" after 'end's to clarify. This is not needed in pythonic (or whatever name it can be given) format:

Code: Pascal  [Select]
  1. while not Terminated do begin
  2.   if not self.Enabled then
  3.     BREAK;
  4.   if SomeValue >= 0 then begin
  5.     lastItem := 0;
  6.     for aitem in SomeArray do begin
  7.       aItem := lastItem + aItem * SomeValue;
  8.       lastItem := aItem;
  9.       end;
  10.     end //for has ended above here;
  11.   else begin
  12.     for aitem in SomeArray do
  13.       aItem := aItem * SomeValue;
  14.     end;
  15.   [...] //else has ended above here;
  16.   end;
  17. [...] //while has ended above here;

Also, we use similar formatting for var, const and type declarations (without needing any begin or end):
Code: Pascal  [Select]
  1. var
  2.   i: integer;
  3.   s: string;
  4.   r: real;
  5.  

My only submission is this alternative format should be acceptable in posts here.
« Last Edit: July 22, 2019, 10:47:14 am by rnfpc »

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7302
Re: Formatting in FreePascal
« Reply #11 on: July 22, 2019, 10:41:22 am »
This way, to scan structure validity you have to constantly move your eyes from left to right to catch all those begins.  Pascal isn't a tennis game.
The visual braces are build by "if [...]" and "end". You can see it from the intendation, that its a block. So there has to be a begin in the end of the line, no need to search for it.


Indentation is a tool only. The begin is the real block structure.

Anyway, I've used the style for a while (many schools taught it in the eighties/early nineties), and there is also a corresponding C style, and I found myself constantly scanning for missing or forgotten begins (or {'s). It is IMHO simply not worth the  single line savings.

And bear in mind that I'm originally modula2er, which omits BEGIN for non procedure blocks and thus has indentation close to this style. (actually a popular alternative was to put all statements of the block and the END on the same indentation level)

But in M2 you can rely on it, so while visually the same, which makes it  totally different in practice . Same as Python, there the indentation must be right(*), otherwise it won't work, so you can "rely" on it. 

Stronger even, my general opinion is that I don't care that much about indentation, as long as begin (and ELSE) is on a single line.

(*) whatever your opinion is on that.
« Last Edit: July 22, 2019, 10:50:33 am by marcov »

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7302
Re: Formatting in FreePascal
« Reply #12 on: July 22, 2019, 10:48:09 am »
We often have to use "//do" after 'end's to clarify. This is not needed in pythonic (or whatever name it can be given) format:

It is, since such comments are mostly used when rebalancing (after a codebase or nesting the block deeper). And then you can't rely on indentation being correct.
« Last Edit: July 22, 2019, 11:03:16 am by marcov »

lucamar

  • Hero Member
  • *****
  • Posts: 1948
Re: Formatting in FreePascal
« Reply #13 on: July 22, 2019, 10:48:48 am »
I have tested lots of formatting styles (to the point of (re)formatting each function in a unit in a different way) and in the end I settled (returned) to one like PascalDragon's.

For common readability one shouldn't deviate (or not too much) from the style of the rest of the code-base or the agreed upon rules, if working with others, but in the end it's all a question of personal preference.

For example while I find constructions of this type
Code: Pascal  [Select]
  1.   if something then
  2.   begin
  3.     {... some code ..}
  4.   end
  5.   else
  6.   begin
  7.     {... code some ...}
  8.   end;
cumbersome, others (as can be seen in previous posts) swore by them. But then, I tend to allow for deeper nesting while others prefer shallow nesting and earlier exits  (like in the famous "if condition then Exit" vs. "if contrary then begin .." controversy).

A question of to what you're accustomed, I guess :)

What is realy important, IMHO, is that, whatever style you use, it  must be used consistently and coherently. Otherwise it produces that jarring impression that makes one reach for the JCF as a frst measure :D
« Last Edit: July 22, 2019, 10:56:15 am by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.2/2.0.4  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

BrunoK

  • Full Member
  • ***
  • Posts: 158
  • Retired programmer
Re: Formatting in FreePascal
« Reply #14 on: July 22, 2019, 10:56:21 am »
Additionally, statements that use then exit, then continue, then break or then goto Somelabel should always be written on 2 lines like :
Code: Pascal  [Select]
  1.   if not self.Enabled then
  2.     BREAK;
  3.   if not self.Enabled then
  4.     exit;
  5.   if not self.Enabled then
  6.     continue;
  7.   if not self.Enabled then
  8.     goto SomeLabel;
  9.  
Reason : in all these cases there is a real code flow change and enhancing the visual aspect helps find errors.
Having an important instruction just stuck at the end of a line makes code more difficult to read.

AS for then ... end indentation, it is convenient to align the end under the if or the matching begin so moving the cursor up or down will help visually detect the boundaries of block code.

But this is a personal point of view and I have examples of my own patches in Lazarus Trunk that have been changed by the TEAM to something else and has become more difficult to read.
Lazarus trunk r. 59978/03.01.2019 (+/- patches regarding enabled, TScrollBar, TCursorImage). FPC 3.0.4 32 bits. (+heaptrc with leaked ClassName+Revisited TList) , Windows 10 Pro x64 (v. 1803)