Recent

Author Topic: Code reuseability  (Read 1030 times)

MortenB

  • Jr. Member
  • **
  • Posts: 63
Code reuseability
« on: November 23, 2025, 08:41:51 pm »
A direct wish for extended compiler functionality.
In certain scenarios, a lot of code is identical between procedures and functions, but unless making a file and using {$I FileName}, the code have to be written double up, or even more than double up.
I would like to suggest a similar pattern of {$Region 'Name'} and {$EndRegion}:
Code: Pascal  [Select][+][-]
  1. {$CodeBlock 'Name'}
  2.   // Code for identical reuse here...
  3. {$EndCodeBlock}

And then later where you want to insert that exact codeblock on compiletime:
Code: Pascal  [Select][+][-]
  1. Procedure SomeFunctionality(...);
  2.   Var
  3.      Something:Integer;
  4.   Begin
  5.     Something := High(MyArray);
  6.    {$ReuseCodeBlock 'Name'}
  7.   End;

440bx

  • Hero Member
  • *****
  • Posts: 6075
Re: Code reuseability
« Reply #1 on: November 23, 2025, 08:46:55 pm »
It sounds like what you should do is to create a procedure (or function) out of the CodeBlock that way you can reuse it anywhere you like.

HTH.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

LemonParty

  • Sr. Member
  • ****
  • Posts: 393
Re: Code reuseability
« Reply #2 on: November 23, 2025, 09:09:04 pm »
You may use macros. For other cases {$I Filename.pas} is reasonable fit. If this feature will be implemented in compiler how such code will be handled during debug?
« Last Edit: November 23, 2025, 09:14:40 pm by LemonParty »
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12099
  • Debugger - SynEdit - and more
    • wiki
Re: Code reuseability
« Reply #3 on: November 23, 2025, 09:41:32 pm »
I don't recommend it (in fact I recommend NOT to  do the following), but...

You can use IFDEF and INCLUDE => include the unit itself.

Say you have unit1.pas
Code: Pascal  [Select][+][-]
  1. unit unit1;
  2. //...
  3.  
  4. {$IFDEF BLOCK1}
  5.    // my code block
  6. {$ENDIF}
  7.  
  8. // use the block
  9. {$DEFINE BLOCK1} {$I unit1.pas} {$UNDEF BLOCK1} // undef so it wont be defined if you use block 2
  10.  

Btw, I call the above shooting yourself in the foot. You may not notice at first, if you are pre occupied, but let it come to debugging... Each time you step through the code, you will be stepping in the IFDEF block. And you wont have any info on which method it is embedded in. (Yeay, you can go to the caller in the stack, and see what it called, if it wasn't in a proc/event variable...

IMHO, in the long run you stand to loose more time than you maybe gain at first. But that is my 2 cents.

MortenB

  • Jr. Member
  • **
  • Posts: 63
Re: Code reuseability
« Reply #4 on: November 23, 2025, 09:59:44 pm »
It sounds like what you should do is to create a procedure (or function) out of the CodeBlock that way you can reuse it anywhere you like.

HTH.

My problem is that I have already tried that, I made a wrapper, but I want the code to be inlined as well, and the compiler refuse to do inlining on 3 generic functions when one is referencing another.
Removing the wrapper, and the inlining works.
Basically copy and paste instead of making a wrapper also make the inlining work, but then a lot of duplicate code.
The duplicate code cannot be put in a separate procedure or function due to the generic properties and inlining fails.

MortenB

  • Jr. Member
  • **
  • Posts: 63
Re: Code reuseability
« Reply #5 on: November 23, 2025, 10:05:11 pm »
You may use macros. For other cases {$I Filename.pas} is reasonable fit. If this feature will be implemented in compiler how such code will be handled during debug?

Such code should be easy enough to handle by the debugger. If there is a bug, then simply show the bug where it is:
With the codeblock directive, the debugger already has the codeblock available and can simply display the sourcecode in brackets at the right place. No big issue there.

cdbc

  • Hero Member
  • *****
  • Posts: 2606
    • http://www.cdbc.dk
Re: Code reuseability
« Reply #6 on: November 23, 2025, 10:25:25 pm »
Hi
As @440bx said, that's exactly what procedures and functions are for!
Forgive me, but at what level are you coding, beginner, intermediate or seasoned?!?
I've been programming pascal for 41 years and never needed that  %)
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

440bx

  • Hero Member
  • *****
  • Posts: 6075
Re: Code reuseability
« Reply #7 on: November 23, 2025, 11:24:35 pm »
@MortenB,

You can accomplish that CodeBlock thing you described simply by putting the code in an include file then including the file wherever you need the code.

For the record, it's very unlikely that inlining will really save a significant amount of time if the amount of code that is being inlined is large.  The reason for this is inlining only saves the creation and taking down of a stack frame which is negligible if the function/procedure is over several hundred instructions long.

Inlining can make a big difference when the amount of code is small and it is executed a very large number of times.  It doesn't sound like that's the case you described.

Anyway, whichever the case may be, an include file will do what you described.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Handoko

  • Hero Member
  • *****
  • Posts: 5515
  • My goal: build my own game engine using Lazarus
Re: Code reuseability
« Reply #8 on: November 24, 2025, 03:41:20 am »
It sounds like what you should do is to create a procedure (or function) out of the CodeBlock that way you can reuse it anywhere you like.

I prefer to make it a procedure/function too. It will be more readable especially if you give it a good name. If the code can be used for other projects, make it an unit, module or library.

I personally do not use {$I Filename} but I heard it is commonly used for managing cross platform part of the code.
« Last Edit: November 24, 2025, 03:47:42 am by Handoko »

Thaddy

  • Hero Member
  • *****
  • Posts: 18729
  • To Europe: simply sell USA bonds: dollar collapses
Re: Code reuseability
« Reply #9 on: November 24, 2025, 07:18:44 am »
A direct wish for extended compiler functionality.
This is already possible and is also used in e.g. the implementation section of sysutils and math.

An example is the include file syshelpf.inc  in rtl/objpas/sysutils
« Last Edit: November 24, 2025, 02:13:16 pm by Thaddy »
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

MortenB

  • Jr. Member
  • **
  • Posts: 63
Re: Code reuseability
« Reply #10 on: November 24, 2025, 03:34:25 pm »
Hi
As @440bx said, that's exactly what procedures and functions are for!
Forgive me, but at what level are you coding, beginner, intermediate or seasoned?!?
I've been programming pascal for 41 years and never needed that  %)
Regards Benny

Coding level... I would say pretty much seasoned.
I can create anything I want to. The question wasn't about what I need, it was about something that I would consider to be very nice to have as a possibility.
It is kind of the same with Generics. We don't need them, but after getting to work with generics, I can not think of willingly going back to the time before generics.
The code-block suggestion isn't something I need to make my code work, it is something I would welcome as a tool to streamline coding and not end up with identical code-blocks at many places.
Of course, I can make an Include-file, but then the code isn't directly visible.
I was also asking for Generics in Pascal (Turbo Pascal) back in the 80s... but the answer back then was also: We don't need it.

440bx

  • Hero Member
  • *****
  • Posts: 6075
Re: Code reuseability
« Reply #11 on: November 24, 2025, 03:47:55 pm »
Of course, I can make an Include-file, but then the code isn't directly visible.
That's true but, with your solution it is only visible in one place which is the same when using an include file.  The only difference is that in one case the code is present in the same file instead of in a different file.

Lastly, if the code is in a different file, it is usually easier to find it than when it is "somewhere" intermingled in the source.

Honestly, I don't see any benefits to your suggestion.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 18729
  • To Europe: simply sell USA bonds: dollar collapses
Re: Code reuseability
« Reply #12 on: November 24, 2025, 03:49:37 pm »

If you are too lazy to read my remarks here's an excerpt.
An include file is used for all possible float values, because they have the same code.
The float type is adjusted in the interface section based on where the include is (re)- used which is exactly like you asked in the implementation section:
Code: Pascal  [Select][+][-]
  1. {%MainUnit sysutils.pp}
  2. Class Function TFLOATHELPER.IsNan(const AValue: FLOATTYPE): Boolean; overload; inline; static;
  3.  
  4. begin
  5.   Result:=TFloatRec(AValue).SpecialType=fsNan;
  6. end;
  7.  
  8. Class Function TFLOATHELPER.IsInfinity(const AValue: FLOATTYPE): Boolean; overload; inline; static;
  9.  
  10. begin
  11.   Result:=TFloatRec(AValue).SpecialType in [fsInf,fsNinf];
  12. end;
  13.  
  14. Class Function TFLOATHELPER.IsNegativeInfinity(const AValue: FLOATTYPE): Boolean; overload; inline; static;
  15.  
  16. begin
  17.   Result:=TFloatRec(AValue).SpecialType=fsNinf;
  18. end;
  19.  
  20. Class Function TFLOATHELPER.IsPositiveInfinity(const AValue: FLOATTYPE): Boolean; overload; inline; static;
  21.  
  22. begin
  23.   Result:=TFloatRec(AValue).SpecialType=fsInf;
  24. end;
  25.  
  26. Class Function TFLOATHELPER.Parse(const AString: string): FLOATTYPE; overload; inline; static;
  27.  
  28. begin
  29.   Result:=StrToFloat(AString,DefaultFormatSettings);
  30. end;
  31.  
  32. Class Function TFLOATHELPER.Parse(const AString: string; const AFormatSettings: TFormatSettings): FLOATTYPE; overload; inline; static;
  33.  
  34. begin
  35.   Result:=StrToFloat(AString,AFormatSettings);
  36. end;
  37.  
  38. Class Function TFLOATHELPER.Size: Integer; inline; static;
  39.  
  40. begin
  41.   Result:=SizeOf(FLOATTYPE);
  42. end;
  43.  
  44. Class Function TFLOATHELPER.ToString(const AValue: FLOATTYPE): string; overload; inline; static;
  45.  
  46. begin
  47.   Result:=FloatToStr(AValue,DefaultFormatSettings);
  48. end;
  49.  
  50. Class Function TFLOATHELPER.ToString(const AValue: FLOATTYPE; const AFormatSettings: TFormatSettings): string; overload; inline; static;
  51.  
  52. begin
  53.   Result:=FloatToStr(AValue,AFormatSettings);
  54. end;
  55.  
  56. Class Function TFLOATHELPER.ToString(const AValue: FLOATTYPE; const AFormat: TFloatFormat; const APrecision, ADigits: Integer): string; overload; inline; static;
  57.  
  58. begin
  59.   Result:=FloatToStrF(AValue,AFormat,APrecision,ADigits,DefaultFormatSettings);
  60. end;

So better read proper answers.

This is not the only place where this is used. It is used in the rtl in several other places.
The same include file is used in several places in the same unit, just by changing the meaning in the interface section.
« Last Edit: November 24, 2025, 03:54:48 pm by Thaddy »
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12099
  • Debugger - SynEdit - and more
    • wiki
Re: Code reuseability
« Reply #13 on: November 24, 2025, 04:10:26 pm »
My problem is that I have already tried that, I made a wrapper, but I want the code to be inlined as well, and the compiler refuse to do inlining on 3 generic functions when one is referencing another.
Removing the wrapper, and the inlining works.

Interesting...

Rather than asking for a "replacement feature" wouldn't it be better to ask for the original feature (inlining) to be improved?

Of course, I can make an Include-file, but then the code isn't directly visible.

Hence, I suggested to (try to) include the unit itself (recursively).
- Then the code is visible in the unit, inside an IFDEF.
- When the unit is parsed as unit, the IFDEF is inactive
- When the unit is parsed as include, then the IFDEF is active.

But, my example was not complete. The rest of the unit needs to be in an "{$ifNdef BLOCK1}" => so during an include only the block is visible.

Yes, it will be a bit of fiddling, but probably can be made to work...



You may use macros. For other cases {$I Filename.pas} is reasonable fit. If this feature will be implemented in compiler how such code will be handled during debug?

Such code should be easy enough to handle by the debugger. If there is a bug, then simply show the bug where it is:
With the codeblock directive, the debugger already has the codeblock available and can simply display the sourcecode in brackets at the right place. No big issue there.

1) My comment wasn't on macros (though it does apply to macros too / my comment was on include files)

Which btw, why not macros? They are more or less exactly like what you describe with your block?

2) About the debugging.

Yes, the debugger would know the line in the include file (or the macro).

But that line is in several functions. That is the whole purpose, to avoid the copy and paste.

Example
Code: Pascal  [Select][+][-]
  1. //line 20 to 30
  2. {the block}
  3. ...
  4. {end}
  5.  
  6. line 100
  7. procedure foo;
  8. //the block
  9.  
  10. line 150
  11. procedure bar;
  12. //the block
  13.  
  14. line 300
  15. procedure xyz
  16. //the block
  17.  

So you are paused in the block.
The debugger shows you are at line 25. (that is the only place where the line is).

But you do not know, if that is in foo,bar or xyz.

Because its not a call, but compiled into the function, then there is no entry in the callstack that says what the caller is.
(Of course there is a caller in the callstack, and if you jump to the source of that caller, then you can find if it called foo, bar, or xyz / unless it called via a variable, and you don't know whats in the var)



Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12099
  • Debugger - SynEdit - and more
    • wiki
Re: Code reuseability
« Reply #14 on: November 24, 2025, 04:13:38 pm »
About the debugging... I completely overlooked that the current frame will have the name of the function.

But there is some case, just can't recall it exactly. I do remember having to debug some code (not mine) that used macros, and I was stuck with an exception in the macro, and had no way to find the place that the macro was inlined.

Maybe if the same macro is used several times inside the same function...

 

TinyPortal © 2005-2018