Lazarus

Free Pascal => Beginners => Topic started by: coradi on October 29, 2024, 10:30:09 pm

Title: Does a procedure in a procedure have any advantage?
Post by: coradi on October 29, 2024, 10:30:09 pm
Code: [Select]
Procedure  Hallo(n:Byte);

Procedure test;
Var p : Byte;
Begin
p:= 5;
end;

Begin
  Writeln('Hallo, World ',n,'');
end;     
[\code]
Title: Re: Does a procedure in a procedure have any advantage?
Post by: Bart on October 29, 2024, 10:49:08 pm
Well, in your example it doesn't do anything....

Having a nested procedure (as it's called) makes the nestes procedure only visible to the procedure in question.
This could make for cleaner code.

Also, your nested procedure may make use of local variables of the procedure it's nested in, which otherwise would only be possible when passed as a parameter.

Code: Pascal  [Select][+][-]
  1. procedure Log(Lines: TStrings);
  2. var
  3.   i: Integer;
  4.  
  5.   function PrependDate(S: String): String;
  6.   begin
  7.     Result := DateToStr(Now) + ': [' + IntToStr(i) + ']  ' + S;
  8.   end;
  9.  
  10. begin
  11.   for i := 0 to Lines.Count - 1 do
  12.   begin
  13.     writeln(PrependDate(Lines[i]));
  14.   end;
  15. end;

The function PrependDate is only ever needed in the procedure Log, so there is no need to "expose" it.
The nested function also uses the variable i.
(Notice that it would probably be better to just pass i as a parameter to PrependDate in this particular case, but just showing you that in can be done. And it certainly has it's use cases.)

Bart
Title: Re: Does a procedure in a procedure have any advantage?
Post by: Warfley on October 29, 2024, 10:49:53 pm
Two things:
1. Scoping. If you only ever use a function within another function, there is no reason to define it globally. Always try to keep the scope as small as possible.
2. Context. You can access the context of the parent function:
Code: Pascal  [Select][+][-]
  1. procedure Foo(X: Integer);
  2. var
  3.   Y: Integer;
  4.  
  5. procedure PrintXY;
  6. begin
  7.   WriteLn('X: ', X, ' Y: ', Y);
  8. end;
  9.  
  10. begin
  11.   Y:=42;
  12.   PrintXY;
  13. end;
Title: Re: Does a procedure in a procedure have any advantage?
Post by: Curt Carpenter on October 29, 2024, 11:33:45 pm
I think readability is the main advantage since it reminds us of the nested procedure's limited scope.  They can also let us break a long, complex procedure into smaller parts each with a clearly defined function of its own.  Other ways to accomplish those same things of course.
Title: Re: Does a procedure in a procedure have any advantage?
Post by: Thaddy on October 30, 2024, 10:05:27 am
It is also a way to solve (and break off) recursion. But readability is the most important. It has always been part of Pascal.
It predates classes and objects, while performing similar tasks (except inheritance of course): it ties code to a specific scope. Frankly, that is the - and still is - advantage, by design.
Title: Re: Does a procedure in a procedure have any advantage?
Post by: MarkMLl on October 30, 2024, 12:56:11 pm
I'd suggest that it's particularly important if we consider a dialect of Pascal that doesn't allow Turbo-style "writeable constants" (AKA ALGOL "own variables"). Hence something like

Code: Pascal  [Select][+][-]
  1.   procedure initMapView;
  2.  
  3.   var
  4.     scratchLayer: TMapLayer;
  5.  
  6.  
  7.     procedure addArea(const area: TRegionDegs; colour: TColor; opacity: single);
  8.  
  9.     var
  10.       scratchArea: TMapArea;
  11.  
  12.     begin
  13.  
  14.       (* Add an areas object to the layer which will act as a container for     *)
  15.       (* coloured static blocks, returning a reference which may be used        *)
  16.       (* locally.                                                               *)
  17.  
  18.       scratchArea := scratchLayer.Areas.Add as TMapArea; // <------------------------
  19.  
  20.       (* Using that reference which is retained in-scope, set up drawing style  *)
  21.       (* and add features.                                                      *)
  22.  
  23.       scratchArea.FillColor := colour;
  24. ...
  25.     end { addArea } ;
  26.  
  27.  
  28.     procedure addAreas(const areas: TRegionsDegs; colour: TColor; opacity: single);
  29.  
  30.     var
  31.       i: integer;
  32.  
  33.     begin
  34.       for i := 0 to High(areas) do
  35.         addArea(areas[i], colour, opacity)
  36.     end { addAreas } ;
  37.  
  38.  
  39.   begin
  40.  
  41.   (* Add a layer object to the MapView which will act as a container for areas  *)
  42.   (* and tracks, returning a reference which may be used locally.               *)
  43.  
  44.     scratchLayer := MapView1.Layers.Add as TMapLayer;
  45.  
  46.   (* Using that reference which is retained in-scope, add coloured static areas *)
  47.   (* to represent properties or villages which should not be overflown at low-  *)
  48.   (* levels, and an "in-circuit" area within which aircraft should exercise     *)
  49.   (* caution.                                                                   *)
  50.  
  51.     addArea(InCircuit, clYellow, 1/3);
  52.     addAreas(Avoids, clRed, 1/6);
  53. ...
  54.   end { initMapView } ;
  55.  

Once we've got the local reference to the layer, we know that anything else we do is in that context. There's really no need to pass it as a parameter to subsequent procedures (addArea, addAreas and so on), or to start messing around declaring container classes which will never be reused.

Similarly, while initMapView will be called at a fairly high level, there's no need to make addArea, addAreas and so on publicly visible: they're strictly for use locally.

All of this is "Pascal as Wirth intended it": i.e. building on unambiguous scope and visibility rules.

MarkMLl
Title: Re: Does a procedure in a procedure have any advantage?
Post by: Чебурашка on October 30, 2024, 01:10:21 pm
Yes, it improves possibility of code organization significantly.

Often in languages without it, I ended up creating methods with names like this to indicate that subs where intended to be called only by procedure1 (and this is not enforced at all by compiler):

procedure procedure1_sub1();
procedure procedure1_sub2();

procedure procedure1();
begin
  procedure1_sub1();
  procedure1_sub2();
end
Title: Re: Does a procedure in a procedure have any advantage?
Post by: marcov on October 30, 2024, 01:20:34 pm
Moreover if the procedures are relatively short, they can be inlined, making it a substitute for things that other languages use macros for.
Title: Re: Does a procedure in a procedure have any advantage?
Post by: Joanna on October 31, 2024, 03:02:08 pm
Nested procedures are helpful for executing code that will be used more than once only within the procedure. Their advantage is that they don’t clutter the rest of the program.
Title: Re: Does a procedure in a procedure have any advantage?
Post by: wp on October 31, 2024, 03:22:22 pm
On the other hand, nested procedures sometimes can be found inside very long procedures, and they seem like an excuse that no time was taken to find better code. Unit ipHtmlTableLayout, for example, contains the procedure TIpNodeTableLayouter.Calcsize with almost 20.000 lines, among them 6 nested procedures, and one of them having 10.000 lines by itself. Such poorly written code is extremely hard to maintain, in particular when the original author (TurboPower in this examples) has disappeared.

(But I must confess that I wrote some of these monsters myself...)
Title: Re: Does a procedure in a procedure have any advantage?
Post by: Warfley on October 31, 2024, 03:54:51 pm
There is also one thing I must admit wrt. to tooling, that is navigating nested procedures is a pain.

The first thing I do when I setup my Lazarus is pop the project inspector and code explorer into the side bar of the (docked) IDE, so I have all my files and all the functions in the file I'm currently working on visible.

One of the problems with the code explorer (aside from the fact that it's really slow on updating it's view, as well as not updating the currently open function unless you switch windows) is that it does not show you nested procedures.
So you have this really nice window which shows you all the stuff in your file, but only on a global level.

Also I feel that the positioning of nested functions is a bit annoying with being in between the function header and body, which makes it easy to lose track of where you are exactly in the main function or the nested function. A better alternative I think is the way Haskell does it, where the nested functions are below the function:
Code: Pascal  [Select][+][-]
  1. quicksort :: (Ord a) => [a] -> [a]
  2. quicksort [] = []
  3. quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
  4.     where
  5.         lesser = filter (< p) xs
  6.         greater = filter (>= p) xs
Where the nested functions (lesser and greater in this case) are located below the code of the function, so you can read the function from top to bottom without helper code being interleaved
Title: Re: Does a procedure in a procedure have any advantage?
Post by: Joanna on October 31, 2024, 11:39:54 pm
I always indent and comment the end of the nested procedures and it sounds like very bad design to have thousands of lines of code in one.
Maybe code written without oop?
Title: Re: Does a procedure in a procedure have any advantage?
Post by: 440bx on November 01, 2024, 01:23:42 am
I always indent and comment the end of the nested procedures and it sounds like very bad design to have thousands of lines of code in one.
Maybe code written without oop?
There are two reasons to group instructions, they are:

1. A group of instructions accomplishes a specific, well defined logical task.
2. A group of instructions is executed multiple times.

Those are the two reasons instructions are grouped.

Let's start with case 2 above.  If that group is executed in one and only one function/procedure then that group should be nested into that function/procedure to reveal the fact that it is not executed anywhere else.  That gives locality which is important because the programmer doesn't have to wonder what other code in the program depends on that sequence of code.

Case 1 is the really interesting one and the one that most programming languages have not addressed satisfactorily (including Pascal.)  For the sake of a simple explanation and without loss of generality, presume that there are no sequences of code that are executed multiple times.  Also, presume what is the most common case, that the function/procedure is composed of a fairly large number of logical steps.  What follows is what usually happens in most languages, including Pascal. 

The top level function is broken down into a number of functions/procedures and those functions/procedures are then executed in a mostly linear fashion, I say mostly because some may be part of a loop or if statement or some other code that controls how or when the code is executed.   When the programmer reaches that code and sees "SomeFunction(SomeParameter1, SomeParameter2...SomeParameterN), it is quite often necessary for the programmer to "jump" to where "SomeFunction" is implemented to refresh his/her memory to see what the code actually does.  If there are 10,000 lines broken into small "acceptable" pieces to some programmers, that means the 10,000 lines are going to be broken into about 200 individual blocks of code.  That also means that when the programmer is reading the top level function, he/she will have their attention diverted away from the mainline 200 times.  Welcome to spaghetti code and jigsaw-puzzle programming.

The way it should be done is to have a way (a construct of some kind) to group code _inline_ so the programmer can see (and be told) that a sequence of instructions fulfills a specific logical purpose.  This is also a way to have the convenience of inline variables without inline variables and local types and constants that is only applicable to a very short sequence of code.

Inline/anonymous functions/procedures _almost_ fulfill the characteristics of the construct I alluded to above but, very unfortunately they require a "()" to cause them to be executed (because they weren't really designed to be a grouping construct.)

10,000 line functions/procedures are a whole lot better, easier to understand and maintain than functions/procedures broken into hundreds of scattered pieces that have to be mentally re-assembled to see what the function does and how it does it.

IOW, today's commonly accepted and supported programming philosophy is: let's make sure to make the big picture as hard to mentally create as possible.
Title: Re: Does a procedure in a procedure have any advantage?
Post by: MarkMLl on November 01, 2024, 09:04:53 am
I always ... comment the end of the nested procedures

I'd add that that became mandatory with Ada and Modula-2, and was optional ** in ALGOL-60. There's obviously also lots of languages which use if...endif etc., and there's even a risk that some of these were BASIC-like and precede Ada (I /really/ hate the idea that something later accepted as good practice originated in K&K BASIC).

** ALGOL-60 apparently discarded everything after an END to the EOL as a comment. It's difficult to design a successor which mandates that /either/ it's a syntax-checked token/identifier /or/ it's an arbitrary comment: in practice I think the common adoption of // as a comment marker makes it sufficiently easy to append a comment that the ALGOL convention is obsolete.

MarkMLl
Title: Re: Does a procedure in a procedure have any advantage?
Post by: MathMan on November 01, 2024, 11:57:33 am
There are two reasons to group instructions, they are:

1. A group of instructions accomplishes a specific, well defined logical task.
2. A group of instructions is executed multiple times.

...

The top level function is broken down into a number of functions/procedures and those functions/procedures are then executed in a mostly linear fashion, I say mostly because some may be part of a loop or if statement or some other code that controls how or when the code is executed.   When the programmer reaches that code and sees "SomeFunction(SomeParameter1, SomeParameter2...SomeParameterN), it is quite often necessary for the programmer to "jump" to where "SomeFunction" is implemented to refresh his/her memory to see what the code actually does.  If there are 10,000 lines broken into small "acceptable" pieces to some programmers, that means the 10,000 lines are going to be broken into about 200 individual blocks of code.  That also means that when the programmer is reading the top level function, he/she will have their attention diverted away from the mainline 200 times.  Welcome to spaghetti code and jigsaw-puzzle programming.

I can follow your reasoning, but I beg to differ on your final sentence. The human brain unfortunately is not an unlimited stack machine - context will be lost whether you have a large 10k LOC function or a break down as described above. And if one follows (like me) a top down approach to understanding the second approach is easier to grasp (at least for me). But maybe I misunderstood.

The way it should be done is to have a way (a construct of some kind) to group code _inline_ so the programmer can see (and be told) that a sequence of instructions fulfills a specific logical purpose.  This is also a way to have the convenience of inline variables without inline variables and local types and constants that is only applicable to a very short sequence of code.

Inline/anonymous functions/procedures _almost_ fulfill the characteristics of the construct I alluded to above but, very unfortunately they require a "()" to cause them to be executed (because they weren't really designed to be a grouping construct.)

10,000 line functions/procedures are a whole lot better, easier to understand and maintain than functions/procedures broken into hundreds of scattered pieces that have to be mentally re-assembled to see what the function does and how it does it.

IOW, today's commonly accepted and supported programming philosophy is: let's make sure to make the big picture as hard to mentally create as possible.

Why not address the issue at hand - the need to leave the current function context to look up a specific sub-function - to the editor. What I would like to have is a means to let the editor blend in the sub-function source without actually changing the function source - kind of an extended folding. If something like that would be available it would help me tremendously.

Cheers,
MathMan
Title: Re: Does a procedure in a procedure have any advantage?
Post by: MarkMLl on November 01, 2024, 01:09:25 pm
I've just been catching up on my reading and have spotted

Quote
Although many of the optimizations listed in the paper are quite obvious, such as prewarming the CPU caches, using constexpr, loop unrolling and use of inlining, other patterns are less obvious, such as hotpath versus coldpath. This overlaps with the branch reduction pattern, with both patterns involving the separation of commonly and rarely executed code (like error handling and logging), improving use of the CPU’s caches and preventing branch mispredictions, as the benchmarks (using Google Benchmark) clearly demonstrates.

https://hackaday.com/2024/07/13/c-design-patterns-for-low-latency-applications/

That suggests that while moving blocks of code out of a function is a good idea by any standards, it is probably advisable to think about the ordering of the resultant in-scope subfunctions carefully in order to ensure that all critical code is as close together as possible (i.e. often-called subfunctions next to the original code block with error handling etc. somewhat further away).

There's also issues of function setup time: at the sourcecode level it might make sense to move a string or dynamic array into a subfunction, but the effect of that will be hidden prefix and suffix code which might even make a call to the OS's memory manager.

MarkMLl
Title: Re: Does a procedure in a procedure have any advantage?
Post by: 440bx on November 01, 2024, 01:16:32 pm
I don't have the document references at hand but, there have been a fair number of studies that have demonstrated that the easiest "structure" for the human mind to understand is the linear structure.

IOW, Linear things are easy.

The moment things are broken into pieces and the focus has to be diverted to another place, comprehension speed slows down, mistakes happen and the purpose of the pieces (in this case functions) gets mixed  up.  The programmer's mind is also saddled with having to remember the code sequence and, looking at the sequence the functions are called in is not good enough because the code they contain is not visible (gotta go to their definition to see it.)

That's one of the many problems with spaghetti code.  The focus being diverted from one place to another (and then having to go back to the origin.) 

It's like the memory game, cards that are reversed and the subject has to remember the location of the two cards that match.    In programming, the programmer has to remember what each function does as well as often how it does it.  This requires having to jump back to where the function is implemented.  Not only it's counterproductive, it's highly illogical.   Why, if a piece of code is executed in only one place, that piece of code has to reside hundreds (possibly even thousands) of lines away from the location where it is actually used ???  That's absurd.   The only reason the code is broken in "distant pieces" (functions) is because the programmer wants to assign a name to the group of instructions thus (hopefully) reflecting what the group of instructions do (it's logical purpose.)

The simple, obvious, logical thing to do is put that sequences of instructions into a (possibly named) "container" that is inline.  That way, flow remains linear (which is extremely desirable) with the container's name reflecting what the logical purpose of the instructions is.

Ideally, the container would have most of the properties of a function/procedure.  For instance, being able to define constants, types and variables that only exist in the container.

That way, there is no need to jump around the code (with or without the editor's help), types, constants and variables that are only applicable to the group of instructions can be defined locally (instead of cluttering the function with more locals, which are effectively globals in the function) and, in addition to that, the container could be exited early using "exit".    All in one place! as obvious as looking at it.

The problem is, the thought of writing small functions (which often don't even have a clear purpose) has become programming religion.  The net result is, programs that are orders of magnitude more complex than they need to be.
Title: Re: Does a procedure in a procedure have any advantage?
Post by: Joanna on November 01, 2024, 01:33:41 pm
Code: [Select]
@440bx I’ve often resorted to putting parts of code into smaller procedures when I was particularly confused about something. It helps.

It does it easier to understand  if you replace multiple lines of  code that do a particular thing with a procedure.  It makes for easier reading Looking at a few lines of procedure names in a loop.




Title: Re: Does a procedure in a procedure have any advantage?
Post by: MarkMLl on November 01, 2024, 01:44:04 pm
I don't have the document references at hand but, there have been a fair number of studies that have demonstrated that the easiest "structure" for the human mind to understand is the linear structure.

IOW, Linear things are easy.

That is undoubtedly true.

But if you were working through a sourcefile, would you rather encounter a function ReloadBackend() (referring to something elsewhere) or a hundred lines of inline code (no matter how well documented)?

https://github.com/MarkMLl/dsocat/blob/main/frontend/dsofrontendcode.pas 2527 through 2627 apply :-)

MarkMLl
Title: Re: Does a procedure in a procedure have any advantage?
Post by: Thaddy on November 01, 2024, 01:46:07 pm
One important observation is that local procedures/nested procedures predate object pascal.
Title: Re: Does a procedure in a procedure have any advantage?
Post by: MarkMLl on November 01, 2024, 01:48:46 pm
One important observation is that local procedures/nested procedures predate object pascal.

Yes, which is a point I made earlier in the thread.

Also some ALGOL-based systems had an array of "display" registers rather than relying on chained stackframes.

MarkMLl
Title: Re: Does a procedure in a procedure have any advantage?
Post by: 440bx on November 01, 2024, 02:17:48 pm
But if you were working through a sourcefile, would you rather encounter a function ReloadBackend() (referring to something elsewhere) or a hundred lines of inline code (no matter how well documented)?
Why would I prefer to have the code in a place which is _not_ where it is used ???  The one thing I'd like to see is something like this:
Code: Pascal  [Select][+][-]
  1. function TopLevelFunction
  2. begin
  3.   { statements }
  4.  
  5.   Group ReloadBackEnd
  6.   begin
  7.     { reload back end statements }
  8.   end;  { ReloadBackEnd }  { <- if the group of instructions is more than what fits in one screen, approx 50 lines }
  9.  
  10.   { followed by whatever follows "reloadbackend" }
  11.  
  12.   Group NextLogicalGroup
  13.   begin
  14.     { statements }
  15.   end;
  16.  
  17.   { etc }
  18.  
  19. end; { TopLevelFunction }
  20.  
That way my mind isn't diverted to another location to look at the statements that make up "ReloadBackEnd" (presuming ReloadBackEnd is executed only once and in that place.)


Title: Re: Does a procedure in a procedure have any advantage?
Post by: PascalDragon on November 01, 2024, 09:56:58 pm
The one thing I'd like to see is something like this:
Code: Pascal  [Select][+][-]
  1. function TopLevelFunction
  2. begin
  3.   { statements }
  4.  
  5.   Group ReloadBackEnd
  6.   begin
  7.     { reload back end statements }
  8.   end;  { ReloadBackEnd }  { <- if the group of instructions is more than what fits in one screen, approx 50 lines }
  9.  
  10.   { followed by whatever follows "reloadbackend" }
  11.  
  12.   Group NextLogicalGroup
  13.   begin
  14.     { statements }
  15.   end;
  16.  
  17.   { etc }
  18.  
  19. end; { TopLevelFunction }
  20.  

What about this?

Code: Pascal  [Select][+][-]
  1. function TopLevelFunction
  2. begin
  3.   { statements }
  4.  
  5. {$REGION ReloadBackEnd}
  6.   { reload back end statements }
  7. {$ENDREGION}
  8.  
  9.   { followed by whatever follows "reloadbackend" }
  10.  
  11. {$REGION NextLogicalGroup}
  12.     { statements }
  13. {$ENDREGION}
  14.  
  15.   { etc }
  16.  
  17. end; { TopLevelFunction }
  18.  

The IDE will then allow you to collapse these sections (and I think it even remembers which sections are collapsed?)
Title: Re: Does a procedure in a procedure have any advantage?
Post by: 440bx on November 01, 2024, 10:22:43 pm
What about this?

Code: Pascal  [Select][+][-]
  1. function TopLevelFunction
  2. begin
  3.   { statements }
  4.  
  5. {$REGION ReloadBackEnd}
  6.   { reload back end statements }
  7. {$ENDREGION}
  8.  
  9.   { followed by whatever follows "reloadbackend" }
  10.  
  11. {$REGION NextLogicalGroup}
  12.     { statements }
  13. {$ENDREGION}
  14.  
  15.   { etc }
  16.  
  17. end; { TopLevelFunction }
  18.  

The IDE will then allow you to collapse these sections (and I think it even remembers which sections are collapsed?)
I see that as a definite improvement over having the code "relocated" to some other place.

It still falls short of the ideal (which is not hard to implement)  where constants, types and variables can be declared in a region.  Also, there is no way to exit a region because the region is an IDE construct instead of a language construct.  That's why I previously said that anonymous functions come close to what the language should offer.

Don't get me wrong, I consider your suggestion good but, it falls short of what a programming language should offer.
Title: Re: Does a procedure in a procedure have any advantage?
Post by: Joanna on November 01, 2024, 11:00:05 pm
I seldom use it but code folding is an amazing feature that can really tidy up the code . If the procedures are folded they can be accessible without much scrolling.
Title: Re: Does a procedure in a procedure have any advantage?
Post by: Weiss on November 06, 2024, 06:14:20 pm
On a few occasions I ended up "un-nesting" some useful tools which I initially thought are better off encapsulated and out of scope, because it turned out that I need them somewhere else too. Being new, I find it hard to predict how code will evolve. Also, I do not see the improved readability with nesting procedures, it is quite opposite actually, to me anyway. Object's private/public sections kind of makes more sense, they are declared, and if they are also commented this is the most logical and clear, easier to find and review.
Title: Re: Does a procedure in a procedure have any advantage?
Post by: 440bx on November 06, 2024, 06:46:29 pm
<snip> ... because it turned out that I need them somewhere else too.
That's the reason the code should _not_ be nested, because it is used in multiple functions/procedures.


Being new, I find it hard to predict how code will evolve.
I've been programming for 47 (maybe even 48 by now) years and, unless I am dealing with something easy or very similar to something I've written before, how the code will evolve is still hard to predict.  In most cases, a nebulous idea is good enough.

I've come to the conclusion that a program that is important and somewhat complex has to be written _twice_.  The first time to learn about the problem and how to solve it correctly.  The second time to properly/correctly structure the correct solution (which was found the first time,)

The other thing experience has taught me is that "final" designs should be malleable.  The surest way to make a hard to maintain mess is to religiously stick to a "final" design (often because the programmers involved are too afraid that changes will cause the project deadline to be missed.)

Title: Re: Does a procedure in a procedure have any advantage?
Post by: Warfley on November 07, 2024, 07:09:38 pm
On a few occasions I ended up "un-nesting" some useful tools which I initially thought are better off encapsulated and out of scope, because it turned out that I need them somewhere else too. Being new, I find it hard to predict how code will evolve.
The simple answer to this is: Don't try to predict how the code will evolve, because eventually it will go in a different direction anyway.

Start of as simple as possible, and when your needs evolve, change the code accordingly. For example, you can start of with just writing the code into one function. If that function becomes to big, move code into nested procedures. If you need that code at other places to, move that nested procedure into a global procedure and so on.

Don't try to be smart in the beginning and anticipate what is going in where. Write your code knowing that you will have to rewrite most if not all of it eventually, otherwise you will build yourself a prison. This is espeically true when you work with classes. If you build a class structure a certain way because you think it will evolve into that direction, you can easily end up completely overengineering your classes with functionality that anticipates future developments, but these developments never happens, but instead your needs change in a way that all of the design you did so far is actually a hinderance.
So keep things simple, because it's easier to rewrite simple code than to rewrite complicated code.

Also, I do not see the improved readability with nesting procedures, it is quite opposite actually, to me anyway. Object's private/public sections kind of makes more sense, they are declared, and if they are also commented this is the most logical and clear, easier to find and review.
That may be true, but if you only ever work in methods and objects, you restrict yourself in a different way, because now to access the methods you are bound to the object/class you are working in. This results for example quite often in putting code that has absolutely nothing to do with the datastructure of that class, into methods of that class, just because it is convinient.

To give an example of code I wrote myself many years ago: https://github.com/Warfley/AU3IDE/blob/master/Editor/editor.pas#L158
Here is the function to read a config file, it's directly part of the editor which is configured with that information. I did it that way because it was easy to build, but this makes this function extremly hard to maintain, like updating config versions in the future and stuff like that is much harder than if I had a generic config reading function, that returns a configuration which is then loaded into the editor.
Generally this project is a great example on how not to design your program. It puts so many different functionalities into single classes that it makes it extremely difficult to navigate. This file contains just one class and has nearly 2000 lines. This is way to much functionality

So as a general rule of thumb I can say: do as little inside a class/object as possible and if you are not sure if you need something to be a method or not, first start with a function with simple input and ouput, and only when you realize you depend to much on internal state, then move it into a method.

Also note, you have visibility on unit level. Everything you put into the interface part of the unit is "public", everything you put in the implementation part is "private". So by organizing your project into files, you can also enforce visibility
TinyPortal © 2005-2018