Recent

Author Topic: Does a procedure in a procedure have any advantage?  (Read 2076 times)

MarkMLl

  • Hero Member
  • *****
  • Posts: 8039
Re: Does a procedure in a procedure have any advantage?
« Reply #15 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
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

440bx

  • Hero Member
  • *****
  • Posts: 4749
Re: Does a procedure in a procedure have any advantage?
« Reply #16 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.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1234
Re: Does a procedure in a procedure have any advantage?
« Reply #17 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.




✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

MarkMLl

  • Hero Member
  • *****
  • Posts: 8039
Re: Does a procedure in a procedure have any advantage?
« Reply #18 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
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Thaddy

  • Hero Member
  • *****
  • Posts: 16199
  • Censorship about opinions does not belong here.
Re: Does a procedure in a procedure have any advantage?
« Reply #19 on: November 01, 2024, 01:46:07 pm »
One important observation is that local procedures/nested procedures predate object pascal.
If I smell bad code it usually is bad code and that includes my own code.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8039
Re: Does a procedure in a procedure have any advantage?
« Reply #20 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
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

440bx

  • Hero Member
  • *****
  • Posts: 4749
Re: Does a procedure in a procedure have any advantage?
« Reply #21 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.)


(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5759
  • Compiler Developer
Re: Does a procedure in a procedure have any advantage?
« Reply #22 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?)

440bx

  • Hero Member
  • *****
  • Posts: 4749
Re: Does a procedure in a procedure have any advantage?
« Reply #23 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.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1234
Re: Does a procedure in a procedure have any advantage?
« Reply #24 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.
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

Weiss

  • Full Member
  • ***
  • Posts: 187
Re: Does a procedure in a procedure have any advantage?
« Reply #25 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.

440bx

  • Hero Member
  • *****
  • Posts: 4749
Re: Does a procedure in a procedure have any advantage?
« Reply #26 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.)

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Warfley

  • Hero Member
  • *****
  • Posts: 1763
Re: Does a procedure in a procedure have any advantage?
« Reply #27 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