PartialUnit lazarus / 62-General ---------------------------------------------------------------------- Otto · 2020-03-13 17:23 Hello everyone. I would need to know if there was a way to split a "Unit" into at least two different files. For now I'm using the directive  $I ($INCLUDE). Although, in the first approximation, this solution solves the problem it does not use an OOP-type approach. Thank you in advance. Otto. ---------------------------------------------------------------------- eljo · 2020-03-13 17:33 yes move half the code of unit1 to unit2 and add unit2 to unit1's uses clause. Any constrains that prevents you from doing that? ---------------------------------------------------------------------- howardpc · 2020-03-13 17:45 You don't say what your motivation for "splitting" is. One modular approach for GUI apps is to collect visually and logically related controls together on a frame, and code the program logic in the properties and events of the frame, rather than plonking all controls directly on a form. This works particularly well for GUIs based on tabbed controls. Each tabsheet can have its own frame (or frames) and so the functionality for each tabsheet is then in its own self-contained (frame) unit. The main form then only has to consider what needs to happen when the user switches between tabs. It is much easier to debug and test small self-contained frame units than it is to test and debug a form that has sprawling code that covers most of your app's logic because the form unit is the only module you have (so everything gets put in there). ---------------------------------------------------------------------- wp · 2020-03-13 18:07 Look at the source of the LCL and you'll see that it is done exactly this way. Using many include files like in the LCL, however, makes it difficult to follow the code because it is not clear per se to which unit the inc belongs which can only be solved by stringent naming discipline. Therefore, I personally try to avoid include files for source parts (I do use them for defines some times). I suppose you want to split the unit because it is too long. It is not possible to give you general rules because I don't know what's in your unit. For example, when your "huge" unit consists of a base class and several decendant classes I would extract the "base" class into its own unit and all or each of the dependent classes into other unit(s). These dependent units will have to "use" the base unit. When porting TvPlanit I had the case that there were some controls with extremely long and complex drawing routines, i.e. long nested procedures within long nested procedures - and maybe one more level. This was impossible to manage. So I added a "painter" unit with a "painter" class which had all the nested procedures as private methods. So, it is a highly manual work depending on the specific use case. ---------------------------------------------------------------------- Otto · 2020-03-13 18:16 Thank you for your answer. You have correctly focused on an approach that I already use. What I would need to have in addition would be to have: part of the declaration of methods in separate files. In practice, I'd need something like the "partial classes" of C#.  Otto. ---------------------------------------------------------------------- soerensen3 · 2020-03-13 20:57 This is exactly what I'm thinking about for a while now. I came up with a concept of micro units (I'm not good with inventing catchy names). This is actually the same as a unit but you are allowed forward declarations accross units. To realize this I wrote a small example project that uses code tools to merge multiple units into one. You can use it as a pre compiler I think, though I didn't test that yet. I have very little time at the moment but since you asked this question I wanted to use the opportunity to present the concept to you to get an opinion. So whenever you compile your package/project the units are merged into one that is parsed by fpc instead of the original ones. The source is here: https://github.com/soerensen3/pasunitmerge ---------------------------------------------------------------------- Otto · 2020-03-14 08:46 Thank you soerensen3. I'm going to study your source code. As a first impression it seems to be suitable (or adaptable) to what I proposed. As soon as I've tested, I'll let you know. Otto. ---------------------------------------------------------------------- JuhaManninen · 2020-03-14 12:31 Quote from: soerensen3 on March 13, 2020, 09:57:32 pm... I wanted to use the opportunity to present the concept to you to get an opinion. So whenever you compile your package/project the units are merged into one that is parsed by fpc instead of the original ones. Here is an opinion: You try to get around the circular dependency restriction of Pascal. People complain that all code must be put into one unit thus making the language unsuitable for big projects. RAD development makes it even more challenging as all controls and their event handlers go to one unit. I used to share that sentiment. I thought Object Pascal is doomed due to this restriction. Later with Lazarus project I realized that the restriction actually forces a programmer to design his code better. It all boils down to dependency management. Reducing dependencies always improves the code. Pascal allows a circular dependency through implementation section. If you avoid even that and just use one-direction dependencies, the design improves further. Think of design patterns. They have boxes and arrows between them. Do the arrows point from every box to every other box? No, a design pattern typically tries to minimize dependencies. That is the point of a design pattern. Many languages allow every source file to reference every other source file. It can lead to a spaghetti if you are not careful. Your solution is semantically similar with include files. The files are just stitched together. What is the benefit compared to include files? A better solution is to design your code better and avoid circular dependencies. You can accomplish it with abstract base classes and events etc. Please see Lazarus sources as an example. It has much more than one unit yet it is a big project. ---------------------------------------------------------------------- soerensen3 · 2020-03-14 20:23 Thanks for your reply! I was trying to understand what you wrote and about the implications. It sounds logic but in since you take Lazarus as an example, it does not seem to apply there: In main.pp which has 13000 lines(!!!) has a huge list of dependencies, including the installed packages. Shouldn't it be the other way around? The IDE should provide all the abstract base classes and interfaces (which is partly the case with IDEIntf package but not completely) and all the other units and components could be in separate packages that could either be installed or not. Also a file with so many lines is in my opinion very hard to maintain and understand. Lazarus has a couple of very long files and I feel it is very hard for someone new to comprehend and support development of the IDE. Don't get me wrong I love Lazarus (especially the source editor) but I think what you wrote does not apply here or did I get you wrong or maybe I misunderstood the purpose of main.pp? The difference of my solution is that it is more clean than include files because it shows unit dependencies in the uses section for each unit. If you would do it with an include file you would get a problem with overlapping of dependencies. But pasunitmerge is not much more than an experiment because I felt not entirely happy with include files and couldn't get my code split into units small enough to be an improvement over the include files. ---------------------------------------------------------------------- zamronypj · 2020-03-15 06:51 In Fano Framework, if you take a look at its source code I split each class/interface declaration into separate unit file much like how Java or PHP classes declaration. I use VS code mostly so splitting each class as separate unit file not only  helps code readability, it also helps me navigate to any part of repository by using Ctrl+P and just type part of class name. But splitting each class into individual class has drawback too. to use a class you have to remember all individual units. I do not want this. i want the user of library to be able to use a single unit to be able to use the library. This is where include file helps If you take a look at https://github.com/fanoframework/fano/blob/master/src/fano.pas This is the only unit need to be included in uses clause when using library. It contains include files that contains whole library. ---------------------------------------------------------------------- Handoko · 2020-03-15 07:48 I maybe do not fully understand. But I don't think splitting the unit is a good idea unless I split it manually. Here is what I do. For example if I am writing my graphics engine. I want it able to load texture from files so I write LoadJPGTexture. Later the engine has environment effects. So I add FilterDawn and FilterNight. Eventually the unit becomes too crowed, so I decided to manually split it to several units: MyGraphicsEngine.pas, FileImportExport.pas and EffectFilter.pas. The FileImportExport unit can further specialized to have: - LoadJPGTexture - LoadPNGTexture - Load3DModel - LoadWorld And so the FileImportExport will have: - FilterDawn - FilterNight - FilterRain That what I would do. From 1 unit now becomes 3 units. But if I let a tool to split it for me, how would it do? Does it split them in the half or one third? Or per class? Don't you think manually doing it is better because no matter how smart the AI, it will not know which one I want them to be specialized in the future. Also if there are really so much thing in the unit, it means some parts of it need to specialized to its own unit. Why you need to make them micro units not the real units? ---------------------------------------------------------------------- soerensen3 · 2020-03-15 08:52 @handoko: the tool does the opposite merging multiple files into one. So you can manage the files more easily. @zamronypj: i will have a look at fano framework later. Thanks. ---------------------------------------------------------------------- JuhaManninen · 2020-03-15 11:33 Quote from: soerensen3 on March 14, 2020, 09:23:03 pmI was trying to understand what you wrote and about the implications. It sounds logic but in since you take Lazarus as an example, it does not seem to apply there: Dependency management surely applies to every substantial SW project. QuoteIn main.pp which has 13000 lines(!!!) has a huge list of dependencies, including the installed packages. Yes because the IDE (Integrated Development Environment) is huge and it truly has those dependencies. Note that main.pp has no circular dependencies. There is no implementation uses section. Earlier it was even bigger but some code was moved to a new SourceFileManager unit. Refactorings are done all the time to keep the design OK. QuoteShouldn't it be the other way around? The IDE should provide all the abstract base classes and interfaces (which is partly the case with IDEIntf package but not completely) No, the IDE does not provide interfaces, it uses and implements them. Yes, IDEIntf package provides the interface. It may not be complete, please provide a patch to extend it. I promise to look at it. The interface is done by abstract base classes and different Register...() functions etc. Quote... and all the other units and components could be in separate packages that could either be installed or not. All components are in separate packages, most of them in LCL. All units cannot be in separate packages obviously. The IDE has its units and packages have their units. QuoteAlso a file with so many lines is in my opinion very hard to maintain and understand. Lazarus has a couple of very long files and I feel it is very hard for someone new to comprehend and support development of the IDE. A long file is not really a problem. Many small files are equally difficult to navigate. The editor in Lazarus provides 2 features that help with long files: 1. Bookmarks. In Delphi the bookmarks are per file which sucks. In Lazarus they are global and you can jump around without even thinking which file you are in. Helps with big and small files equally. 2. Multiple editor windows showing parts of the same file. It is like editing 2 separate files. Quote... I think what you wrote does not apply here or did I get you wrong or maybe I misunderstood the purpose of main.pp? Maybe you failed to see how big the project is. There are some 2 million lines (guess, somebody check please). Only 13000+ are in main.pp. Also the main uses section shows only a small subset of all units. Note that many of those units are not needed directly by main unit but they have initialization sections and thus must be included somewhere. The vast majority of code is in other units. If you start to solve a bug, the fix most likely goes to some other unit. Please forget main unit for a while and study the whole IDE. QuoteThe difference of my solution is that it is more clean than include files because it shows unit dependencies in the uses section for each unit. If you would do it with an include file you would get a problem with overlapping of dependencies. I don't know what overlapping of dependencies with include files means. Anyway, dependencies are limited by 2 "borders", units and packages. Units allow circular dependencies through implementation section. Packages allow only used-by one directional dependencies. ---------------------------------------------------------------------- JuhaManninen · 2020-03-15 12:04 Quote from: zamronypj on March 15, 2020, 07:51:57 amI split each class/interface declaration into separate unit file much like how Java or PHP classes declaration. I use VS code mostly so splitting each class as separate unit file not only  helps code readability, it also helps me navigate to any part of repository by using Ctrl+P and just type part of class name. I did not study your code yet but I comment anyway: Putting every class into its own unit is very difficult in some cases. Some classes logically depend on each other too deeply for that. For example TreeView and TreeNode classes are in one unit. The dependency is real and logical, not caused by poor design. The separation is possible in languages that allow circular dependencies freely. The danger then is that every source file includes every other file "just in case"... which easily leads to spaghetti code which is more difficult to maintain later. ---------------------------------------------------------------------- Handoko · 2020-03-15 12:05 I prefer a long file instead of multiple small files. I use bookmarks, code explorer, shortcut to jump between procedure/function definition and its 'real' code (Shift+Ctrl+Up), and Ctrl+F to find text. They make navigating the source code easier, no problem so far. Quote from: JuhaManninen on March 15, 2020, 01:04:00 pmPutting every class into its own unit is very difficult in some cases. Some classes logically depend on each other too deeply for that. That is true. I have units that some classes have tight relationship. Separating them will make maintaining much harder. -edit- I forgot to mentioned, Lazarus has folding text feature, maybe that can be useful for you: https://wiki.lazarus.freepascal.org/New_IDE_features_since#Folding_.28 Hiding.29_text_by_selection ---------------------------------------------------------------------- eljo · 2020-03-15 13:01 Quote from: Handoko on March 15, 2020, 01:05:21 pmI prefer a long file instead of multiple small files. I use bookmarks, code explorer, shortcut to jump between procedure/function definition and its 'real' code (Shift+Ctrl+Up), and Ctrl+F to find text. They make navigating the source code easier, no problem so far. Quote from: JuhaManninen on March 15, 2020, 01:04:00 pmPutting every class into its own unit is very difficult in some cases. Some classes logically depend on each other too deeply for that. That is true. I have units that some classes have tight relationship. Separating them will make maintaining much harder. -edit- I forgot to mentioned, Lazarus has folding text feature, maybe that can be useful for you: https://wiki.lazarus.freepascal.org/New_IDE_features_since#Folding_.28 Hiding.29_text_by_selection Actually separating them might be the next best thing. Try using abstract classes instead to set a common interface. ---------------------------------------------------------------------- Otto · 2020-03-15 13:33 Hello everyone. @Handoko Surely you already know it, but for those who do not know it there is also the Lazarus-IDE directive: {%Region} @[All] I'm still studying the codes posted earlier.  As soon as I have finished I will give you an example which, I hope, will clarify my question better. Otto. ---------------------------------------------------------------------- Handoko · 2020-03-15 13:45 @Otto I didn't know {%Region}. I like all my code unfolded maybe because I have a 24" screen. @eljo I ever heard abstract class but because the documentation does not explain it well, I was not interested to explore more. Thank you but so far the module is working good, not now but maybe in the future I will do the code refactoring. ---------------------------------------------------------------------- eljo · 2020-03-15 13:50 Quote from: Handoko on March 15, 2020, 02:45:08 pm@Otto I didn't know {%Region}. I like all my code unfolded maybe because I have a 24" screen. @eljo I ever heard abstract class but because the documentation does not explain it well, I was not interested to explore more. Thank you but so far the module is working good, not now but maybe in the future I will do the code refactoring. think of abstract classes as a way to formalize how your code interacts like any api. A language agnostic abstract class framework is the interfaces. The implementation details are of no importance as long as the api remains stable same way as a pascal if the interface part remains unchanged regardless of the changes on the implementation section the rest of the program will compile with out changes. ---------------------------------------------------------------------- JuhaManninen · 2020-03-15 13:53 Quote from: Handoko on March 15, 2020, 02:45:08 pmI ever heard abstract class but because the documentation does not explain it well, I was not interested to explore more. An abstract class in Object Pascal has at least one virtual abstract method. You should never create an instance of such class but only of its derived classes which override and implement those methods. Actually the compiler lets you create the instance but gives a warning. A run time exception is raised if you call a virtual abstract method. ---------------------------------------------------------------------- zamronypj · 2020-03-15 14:02 Quote from: JuhaManninen on March 15, 2020, 01:04:00 pmQuote from: zamronypj on March 15, 2020, 07:51:57 amI split each class/interface declaration into separate unit file much like how Java or PHP classes declaration. I use VS code mostly so splitting each class as separate unit file not only  helps code readability, it also helps me navigate to any part of repository by using Ctrl+P and just type part of class name. Putting every class into its own unit is very difficult in some cases. You are correct. The only code that I can not split without causing circular dependency is https://github.com/fanoframework/fano/blob/master/src/DI/Contracts/Dep endencyContainerIntf.pas Because both interface require each other. ---------------------------------------------------------------------- soerensen3 · 2020-03-15 21:56 Quote from: JuhaManninen on March 15, 2020, 12:33:45 pmQuote from: soerensen3 on March 14, 2020, 09:23:03 pmI was trying to understand what you wrote and about the implications. It sounds logic but in since you take Lazarus as an example, it does not seem to apply there: Dependency management surely applies to every substantial SW project. QuoteIn main.pp which has 13000 lines(!!!) has a huge list of dependencies, including the installed packages. Yes because the IDE (Integrated Development Environment) is huge and it truly has those dependencies. Note that main.pp has no circular dependencies. There is no implementation uses section. Earlier it was even bigger but some code was moved to a new SourceFileManager unit. Refactorings are done all the time to keep the design OK. QuoteShouldn't it be the other way around? The IDE should provide all the abstract base classes and interfaces (which is partly the case with IDEIntf package but not completely) No, the IDE does not provide interfaces, it uses and implements them. Yes, IDEIntf package provides the interface. It may not be complete, please provide a patch to extend it. I promise to look at it. The interface is done by abstract base classes and different Register...() functions etc. What I meant was that from my experience it would be better if the IDE would only provide the basics and only a skeleton of UI (like main window with main menu and empty toolbars, settings window etc.). And then provide the interfaces in IDEIntf package (I know it's a package but I still considered it as part of the IDE because it's what is exposed of the IDE to every extension. Everything else is inacessible to other packages). Then make packages for every part of the IDE like source editor, messages window, object inspector, etc. Then it would be possible to change them in a non destructive way and adapt them to your taste and provide them just for the people who want these. If at the moment I want to make changes to let's say the package editor I would have to either completely rewrite it and hide every package window of the IDE or adapt it by modifying it's forms throug code which is more or less a hack. Or I would change the Lazarus source to my needs but then risk that it will not be implemented or that people who are happy the way it is now, are forced to use the now changed version. The separate package files would only communicate to the other windows through the interfaces instead of directly with the IDE windows, as it is the case now (not everywhere I know). That's what I meant where it does not apply that the dependencies go only in one direction. Again this is not meant as a rant but as a discussion!  QuoteQuote    Shouldn't it be the other way around? The IDE should provide all the abstract base classes and interfaces (which is partly the case with IDEIntf package but not completely) No, the IDE does not provide interfaces, it uses and implements them. Yes, IDEIntf package provides the interface. It may not be complete, please provide a patch to extend it. I promise to look at it. The interface is done by abstract base classes and different Register...() functions etc. Thanks, I will try to! ---------------------------------------------------------------------- JuhaManninen · 2020-03-16 10:16 soerensen3, I understand your basic idea. Yes, the IDE could be more modular. When you study the code and try to refactor it, you will notice it is difficult because parts in IDE are truly dependent and hooked together. It is called Integrated Development Environment for a reason. Making it more modular is surely possible but difficult. Parts of the current design are rather good but other parts are not. For example the command line tool LazBuild depends on LCL which is a GUI lib. A nogui widgetset hack was invented to prevent pulling the actual GUI libs in. Not good. The package and project systems depend on LCL units. It will require quite much refactoring to cut that dependency. I have done some refactoring already during few past years. Many units were moved to LazUtils package. LCL dependency was cut out from some units used by LazBuild. Actually LazBuild used to depend on SynEdit, too, but not any more. The effort will continue. Splitting EnvironmentOpts unit into pieces may be the next task. Project and Package systems have similarities and they could share code ... etc. etc. ... Welcome to the modular Lazarus effort. Patches are welcome. [Edit] One more big benefit of splitting IDE's code into packages it that compilation gets faster because Lazarus can compile packages in parallel threads. It makes a big difference with today's multicore CPUs. FPC does not yet support parallel compilation of units but I hope and believe it will some day. ---------------------------------------------------------------------- Otto · 2020-03-17 11:02 Hello everyone. Even though I agree fully that the modular implementation of the FPC has been optimally adopted; I have to admit that there are cases, if very rare, where a more flexible approach is to be preferred. I also include the use of the {$include} directive in cases of flexibility. I give a short example to better illustrate a particular case. Of course, the example is not to be considered restrictive is only a case chosen to be able to discuss the subject. Suppose we have a project, built with Lazarus-IDE, in which some controls on the form have been "moved" from the creation phase in the RAD to the run-time phase. If you included the converted code within the Form's OnCreate event, everything would work (more or less) well. However, if you want to keep the part resulting from THE RAD creation separate from the rest of the code, you should necessarily try to replicate what has been implemented within the IDE with the "Lazarus Form files". I have not yet investigated the exact method implemented in Lazarus to do this. In the example I reported what I would like us to be able to implement using the FPC or Lazarus. In particular, make possible the declaration of at least 2 PartialUnits in which to distribute at will: method declarations, property assignment, and what else possible. The purpose would be to delete comments and thus make it possible to distribute declarations to different files. I could probably develop a program that would allow the different PartialUnits to be merged into one. This could build the derived code with a standard version of FPC. If we wanted to, we could later integrate the code of that program within the IDE-Lazarus through the use of any directives. But before I begin the development of such a program, I would like to know the opinions of other programmers much more experienced than I do. Also because something similar may have already been developed or it could be a bad idea. unitmain.pas : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit unitMain;    // PseudoPartial_unitMain {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls; type   { TForm1 }   TForm1 = class(TForm)    BtnClose: TButton;    Panel1: TPanel;    procedure BtnCloseClick(Sender: TObject);    procedure FormCreate(Sender: TObject);  // PseudoPartial_FormCreate  private   public   end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.BtnCloseClick(Sender: TObject);begin  Close;end; procedure TForm1.FormCreate(Sender: TObject);   // PseudoPartial_FormCreatebegin  (* PseudoPartialUnit *) {%region}  {$include unitmainlfm.pas}   {%endregion}end;     // PseudoPartial_FormCreate end.     // PseudoPartial_unitMain         unitmainlfm.pas : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i (*unit unitMain;        // PseudoPartial_unitMain {$mode objfpc}{$H+} // interface // uses // type // var implementation { TForm1 } procedure TForm1.FormCreate(Sender: TObject);  // PseudoPartial_FormCreatebegin*)// Component serialized as Pascal - Begin  // Format version 1  Name := 'Form1';  Panel1 := TPanel.Create(Self);  BtnClose := TButton.Create(Self);  Left := 338;  Height := 512;  Top := 137;  Width := 512;  BorderStyle := bsNone;  Caption := 'Form1';  ClientHeight := 512;  ClientWidth := 512;  OnCreate := @FormCreate;  Position := poDesktopCenter;  LCLVersion := '2.0.6.0';  with Panel1 do  begin    Name := 'Panel1';    Left := 0;  Height := 512;    Top := 0;    Width := 512;    Anchors := [akTop..akBottom];    ClientHeight := 512;    ClientWidth := 512;    Color := clOlive;    ParentColor := False;    TabOrder := 0;    Parent := Self;    with BtnClose do    begin      Name := 'BtnClose';      Left := 432;      Height := 25;      Top := 8;      Width := 75;      Caption := 'Close';      OnClick := @BtnCloseClick;      TabOrder := 0;      Parent := Panel1;    end;  end;  // Component serialized as Pascal - End(*end;  // PseudoPartial_FormCreate end.  // PseudoPartial_unitMain*) Original version in Italian. Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Se bene io sia d’accordo pienamente sul fatto che l’implementazione modulare del FPC sia stata adottata in maniera ottimale; devo ammettere che ci siano casi, se bene molto rari, in cui un approccio più flessibile sia da preferirsi. Io includo anche l’utilizzo della direttiva {$include} nei casi di flessibilità. Riporto un breve esempio per illustrare meglio un caso particolare. Ovviamente l’esempio non è da considerarsi restrittivo è solo un caso scelto per potere discutere sull’argomento.Supponiamo di aver un progetto, realizzato con Lazarus- IDE, nel quale alcuni controlli del form siano stati “spostati” dalla fase di creazione nel RAD alla fase di runtime.Se si includesse il codice convertito all’interno dell’evento OnCreate del Form, tutto funzionerebbe (più o meno) bene. Se, però, si volesse mantenere separata la parte derivante dalla creazione RAD dal resto del codice si dovrebbe per forza cercare di replicare ciò che è stato implementato all’interno dell’IDE con i “Lazarus Form file”. Non ho ancora indagato sull’esatto metodo implementato in Lazarus per fare ciò.Nell’esempio ho riportato quello che mi piacerebbe che si potesse implementare usando il FPC o Lazarus. In particolare rendere possibile la dichiarazione di almeno 2 PartialUnit nelle quali  distribuire a piacimento: le dichiarazioni dei metodi, l’assegnazione delle proprietà e quant’altro possibile. Lo scopo sarebbe quello di eliminare i commenti e rendere così possibile la distribuzione delle dichiarazione in file diversi. Probabilmente potrei sviluppare un programma che permettesse di fondere le diverse PartialUnit in un’unica sola. In tal modo il codice derivato potrebbe essere compilato con una versione standard di FPC. Se si volesse si potrebbe, in seguito, integrare il codice di tale programma all’interno del IDE- Lazarus tramite l’uso di eventuali direttive.Però prima di cominciare lo sviluppo di un tale tipo di programma, vorrei conoscere i pareri di altri programmatori molto più esperti di me. Anche perché potrebbe essere già stato svilupato qualcosa di simile oppure potrebbe essere una pessima idea. ---------------------------------------------------------------------- Otto · 2020-03-17 11:22 @soerensen3 Hi. Your code is definitely interesting, unfortunately I have not yet managed to compile it. I think I'm missing a few packages. Otto. ---------------------------------------------------------------------- Handoko · 2020-03-17 11:32 Maybe I still don't fully understand but if I want to separate the form creation code I will do like this: On the MainForm's OnCreate event: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses   InitAllForm //, ... , ... procedure TForm1.FormCreate(Sender: TObject);begin  InitMainForm(self);end; And this is InitAllForms.pas: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Unit InitAllForms; interface uses  Classes, SysUtils //, ... , ...  ; procedure InitMainForm(aForm: TForm);procedure InitLoginForm(aForm: TForm);procedure InitConfigForm(aForm: TForm); implementation procedure InitMainForm(aForm: TForm);begin  with aForm do  begin    Name := 'Form1';    Panel1 := TPanel.Create(aForm);    BtnClose := TButton.Create(aForm);    Left := 338;    Height := 512;    Top := 137;    Width := 512;    BorderStyle := bsNone;    with Panel1 do    begin      Name := 'Panel1';      Left := 0;      Height := 512;      Top := 0;      Width := 512;    end;  // ...  end;end; procedure InitLoginForm(aForm: TForm);begin  with aFrom do  begin    // ...  end;end; procedure InitConfigForm(aForm: TForm);begin  // ...end; ---------------------------------------------------------------------- Otto · 2020-03-17 12:54 Thank you Handoko for your opinion. I may have made a mistake in the English translation that led you to believe that the example was of some importance. The example that is carried is trivial, in itself it is useless. (-: Predicting this possibility I had attached the Italian version. :-) What I would like to discuss is: the ability to separate parts of code into different files without creating further clutter and possibly without making any changes to the FPC compiler. Otto. ---------------------------------------------------------------------- mercurhyo · 2020-03-17 13:32 hmm... Just passing by I wanted to recall why units were invented: SIMPLY because in the early times of programming, just after computers addressed more than 64K blocks of rams, the concept of units raised. Each unit did not have the ability to go larger than 64Kb of ONE segment code. Nowadays, you could even make a 4Gb singleton unit encapsulating the biggest application in your Wonderland's nightmares! So, units and how they 'integrate' have become compiler's builders teams "tradition" just helping to clarify lost minded programmers. That said, I love to write different units. It's nice and cool for maintenance, and STRUCTURED minds. However it sprays no longer the fear to overflow 64Kb ram segments on a flat memory model! Splitting 'interface' and 'implementation' in 2 separate files, like modula 2 (pascalish) compilers do, is just convenient to bring a PREPROCESSOR, and would need most of the time 2 compilation passes, where pascal compilers just need one pass. LET IT BE! then, continue to run the TRADITION, it is NOT important anymore!!! it's just tradition  around vanished/disapeared segments from the 16bits world ---------------------------------------------------------------------- JuhaManninen · 2020-03-17 16:25 Quote from: Otto on March 17, 2020, 01:54:29 pmThe example that is carried is trivial, in itself it is useless. I think everybody understood that. QuoteWhat I would like to discuss is: the ability to separate parts of code into different files without creating further clutter and possibly without making any changes to the FPC compiler. Handoko just showed you how to separate parts of code into different files without creating further clutter. It is as clear and intuitive as it gets. UnitMain "uses InitAllForm" which does the job. You can see directly from the code what uses what. Your solution has no indication of the relationship. How does your pre-parser know which units must be stitched together? Then the obvious question : what is the benefit compared to .lfm files? I have a feeling you try to solve a problem that does not exist. I may be wrong of course. ---------------------------------------------------------------------- Handoko · 2020-03-17 16:32 I haven't fully solved the separation issue. Here is the thing I don't know how: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i       ButtonClose.OnClick := @BtnCloseClick; I only passed the self (which is the form), but not the ButtonClose. I can put the mainform.pas in the InitAllForm's uses clause but that won't be good. ---------------------------------------------------------------------- JuhaManninen · 2020-03-17 16:50 Quote from: Handoko on March 17, 2020, 05:32:58 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ButtonClose.OnClick := @BtnCloseClick;I only passed the self (which is the form), but not the ButtonClose. I can put the mainform.pas in the InitAllForm's uses clause but that won't be good. Yes, event handlers and their assignments should be in MainForm. It is logical and intuitive, even if the GUI is built by code somewhere else. The handler can then call code in another unit if need be for encapsulation. ---------------------------------------------------------------------- Otto · 2020-03-17 20:21 @JuhaManninen Hello and thank you for your answer.  - Now I think I made some mistakes when translating into English. - I repeat the problem is not how to separate the Units with the traditional methods. In fact, as I said before, I am not looking for a solution to a problem. The problem itself doesn't exist. The topic I was trying to discuss was about: the possibility of introducing PartialUnits in Lazarus (not necessarily in the FPC). PartialUnits would maintain an Object Oriented approach and would be something similar to the "Partial Class" of C#.  The example I have reported contains comments, now deleting them would get what I would have liked to describe. At present this would naturally give a compilation error. I could be wrong, but I think the mercurhyo user understood the meaning of my question (perhaps he read the Italian version). I've only mentioned C# because it's part of the languages I know, not to begin with a discussion between who is better between FPC and C#. I hope I didn't involuntarily offend someone. Otto. ---------------------------------------------------------------------- mercurhyo · 2020-03-17 21:12 @Otto https://www.freepascal.org/docs-html/prog/progse30.html I think it is what you are actualy talking about In delphi world people write syntax like uses   MyUnit.thisfunction; (* just a fake example to make you understand *) to pick up what they need inside an unit. In FreePascal people write syntax like: uses   MyUnit; the linker decides what to cleanup when the switches >> -CX and -XX are given on the command line or checked in the project options, 'Compilation and linking' so you do not have to care when you release an optimized app debug stripped (off) ---------------------------------------------------------------------- howardpc · 2020-03-17 22:37 As I wrote in reply #3, you can implement your idea of "partial units" for GUI apps in an object oriented way by use of a frame (or frames). In place of the panel and button in your LFM-style "partial unit" you use a frame. This replaces a single monolithic form unit containing everything, splitting it out into a slim form unit with little more than an OnCreate handler and a separate frame unit with the panel/button functionality. Two modularised units in place of one. Where you need other modules of functionality you simply add further frames as "partial units". So three or more modularised units in place of one. Non-GUI functionality (database CRUD, business rules etc.) is provided by separate engine units in the normal way, perhaps associated with a further frame unit or two to provide more bits of the GUI. All this compiles and works well using only existing capabilities of FPC and Lazarus. See the almost do-nothing example, based on your code, in the attachment. ---------------------------------------------------------------------- PascalDragon · 2020-03-18 08:38 Quote from: Otto on March 17, 2020, 12:02:00 pmIf you included the converted code within the Form's OnCreate event, everything would work (more or less) well. However, if you want to keep the part resulting from THE RAD creation separate from the rest of the code, you should necessarily try to replicate what has been implemented within the IDE with the "Lazarus Form files". I have not yet investigated the exact method implemented in Lazarus to do this. If you're interesting in learning more about this I'd suggest you to look at TReader and the RTTI in general. ---------------------------------------------------------------------- Otto · 2020-03-18 11:17 I will respond in separate posts to reduce the risk of confusion. @mercurhyo Thank you mercurhyo. That is exactly what I was referring to. This "SMARTLINK" feature should certainly be used to implement the theoretical concept of PartialUnits. In essence, the idea of PartialUnits would be nothing more than the concept of "Divide et impera" applied to a single Unit while always maintaining an OOP-type approach. I would have a question: What is the "MyUnit.thisfunction;" syntax used by Delphi called? Looks a lot like the syntax that is used in C# (.Net in geneneral) to access the sub-Classes. ---------------------------------------------------------------------- Otto · 2020-03-18 11:18 @howardpc Thank you howardpc, for your response. I also use frames a lot, both in "standard" and "custom" version. As you said, they specialize in GUI usage. As I said, I led by example to discuss the use of PartialUnits in general. What I'm particularly interested in is: the use of PartialUnits even in areas other than the GUI. I chose a GUI-type example so that it was easy for everyone to have a topic to display (even on the screen of our own PC). However, thank you for your intervention, it will certainly help to clarify the scope of discussion. I also thank you for giving me the correct definition, in English, of the kind of example I brought: "do- nothing example". ---------------------------------------------------------------------- Otto · 2020-03-18 11:19 @PascalDragon Thank you very much for your suggestion PascalDragon, I will definitely study what you suggested. I also thank you for quoting my whole sentence; where I had tried to explain the exact purpose of my "do-nothing example". Otto. ---------------------------------------------------------------------- mercurhyo · 2020-03-18 12:32 Quote from: Otto on March 18, 2020, 12:17:54 pmI will respond in separate posts to reduce the risk of confusion. @mercurhyo Thank you mercurhyo. That is exactly what I was referring to. This "SMARTLINK" feature should certainly be used to implement the theoretical concept of PartialUnits. In essence, the idea of PartialUnits would be nothing more than the concept of "Divide et impera" applied to a single Unit while always maintaining an OOP-type approach. I would have a question: What is the "MyUnit.thisfunction;" syntax used by Delphi called? Looks a lot like the syntax that is used in C# (.Net in geneneral) to access the sub-Classes. Unfortunately, at the moment, SMARTLINK only works on applications (standalone executables) it does not work on libraries that you create. it's explained somewhere on the wiki, and it is due to compiler limitations (the compiler do not work with an artificial intellig. neuronal). SO it is stable!!! and SAFE! .... maybe one day, with dynamic packages instead of static, let say, around 2030 ---------------------------------------------------------------------- mercurhyo · 2020-03-18 12:38 @Otto the modula2 pascalish compiller : FROM thisunit IMPORT thatvariable, thatprocedure, thatfunction; the delphi compiler uses  thisunit.thatvariable, thisunit.thatprocedure.... etc so it is NOT a C# concept, it is a Modula 2 concept, ported back to C# and Delphi to import parts of units, manualy, where FreePascal decide what to import and what to clean with SMARTLINK many things people think they came from C, and ... ohoh SURPRISE! they came from Pascal  The only concept my old bones know coming from C world, so far, is the concept of templates/generics, all the other concepts came from pascal world and where adapted to C world ---------------------------------------------------------------------- Otto · 2020-03-18 17:18 @mercurhyo Hello mercurhyo. I had heard of Modula-2, but I didn't know it was part of the ancestors of C#. I knew that C# was part of the Pascal “phylum”, more precisely it was derived from a “test cross” experiment between Delphi, C++, Java, and so on. Searching the internet with Duckduckgo.com I found a Modula-2 → FPC  converter (Modula-2 to Free Pascal translator), but I think it's not opensource. Perhaps by 2031 there will be a {$mode Modula-2} directive within the FPC. Otto. ---------------------------------------------------------------------- winni · 2020-03-18 18:17 Hi! C#  was created by Anders Hejlsberg, the  man who coded Turbo Pascal. Modula2 was used in the 90s when there was no real progress fpr Pascal. This changed when Delphi appeared on the scene. With the start of Delphi 2 you had 32-Bit-support. And with fpc/Lazarus you had Pascal for Linux and Mac. Modula 2 is dead and a historic episode. Oberon never came out of the ETH Zürich and some other universities. Winni ---------------------------------------------------------------------- lucamar · 2020-03-18 19:25 Quote from: Otto on March 18, 2020, 06:18:22 pmPerhaps by 2031 there will be a {$mode Modula-2} directive within the FPC. There are very things Modula-2 has that modern Pascal hasn't, most notably co-routines, but the sintaxes are different enough that a "Modula-2" mode would be a little sintactic nightmare, much worse than it already is with the "MacPas" mode. Note also that Modula-2 is, by now, mostly of historical interest, there are no great code-bases on it, and what there is is easily translatable to modern Pascal; so there's little interest in such a mode. ---------------------------------------------------------------------- winni · 2020-03-18 20:08 Hi! There were a lot of advantages in Modula-2. I miss the endif, endfor .... This helps you realy at the end of a long procedure through the Pascal end Jungle. And the selective import was a great progress: If you needed only one ore two procedures from a unit aka module you only imported them. One can keep this ideas in mind. But Modula-2 is an enfant perdu. Winni ---------------------------------------------------------------------- Otto · 2020-03-18 20:34 Personally I would have no interest in it being introduced {$mode Modula-2}. (-: 2031 would be one year after mercurhyo's scheduled date for the introduction of dynamic packages :-). While I would be very interested if positive features from other languages were introduced, even changing them heavily. For example, add endif endfor as comments and automatically, but above all by introducing PartialUnits. ---------------------------------------------------------------------- garlar27 · 2020-03-18 22:52 Quote from: winni on March 18, 2020, 09:08:32 pmThere were a lot of advantages in Modula-2. I miss the endif, endfor .... This helps you realy at the end of a long procedure through the Pascal end Jungle. Just in case (experienced programmers, please I know you know that), first things first. Normally if my code has more than 3 levels of indentation (except for tries), then I know I have to split the code in methods/functions. Also if the code is way too big for a function maybe I'm doing too much in the same place and again I know I have to split things up. But sometimes split things is not an option. When this happens, in my case an "endfor", "endif", or an "endwhatsoever" is not enough. To tackle that I heavily use code templates like this one (I have a lot to create "for", "repeat" and "while"): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i for $param(ind) := Low($param(SomeArray)) to High($param(SomeArray,sync=2)) do begin   |end; //<---  for $param(ind,sync=1)  ( array $param(SomeArray,sync=2)) // and even have one like thiis to paste whatever i have on the clipboard at the end of something: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  {<--- $Paste() }|   it helps me a lot to navigate my code. ---------------------------------------------------------------------- winni · 2020-03-18 23:29 Hi! I do it the simpler way since I returned from Modula2 to Pascal: Whenever I write a "begin" I add at once after the "end" the reason. So the last lines of a procedure look like:      end; // if <> transparent   end; // for x  end; // for y end; // proc If the IDE could do that for me it would be helpful. Winni ---------------------------------------------------------------------- Otto · 2020-03-19 06:34 Hi winni. Quote from: winni on March 19, 2020, 12:29:40 amHi! I do it the simpler way since I returned from Modula2 to Pascal: Whenever I write a "begin" I add at once after the "end" the reason. So the last lines of a procedure look like:      end; // if <> transparent   end; // for x  end; // for y end; // proc If the IDE could do that for me it would be helpful. Winni That's exactly what I proposed in the previous post. Perhaps it is achievable through a change in the "Jedi Code Format". I used this feature to troubleshoot conversions from other software. Otto. ---------------------------------------------------------------------- soerensen3 · 2020-03-19 08:40 Also there is the outline feature if you use Lazarus: https://wiki.freepascal.org/Lazarus_IDE_Tools#Outline ---------------------------------------------------------------------- soerensen3 · 2020-03-19 08:46 Quote from: Otto on March 17, 2020, 12:22:16 pm@soerensen3 Hi. Your code is definitely interesting, unfortunately I have not yet managed to compile it. I think I'm missing a few packages. Otto. It only uses the Codetools package. I use trunk, maybe that's the difference. Do you get an error? ---------------------------------------------------------------------- wp · 2020-03-19 09:12 Quote from: soerensen3 on March 19, 2020, 09:40:32 amAlso there is the outline feature if you use Lazarus: https://wiki.freepascal.org/Lazarus_IDE_Tools#Outline +1 This feature was a bit distracting in the beginning because of the many colors. But once I got used to it, I use it every day. It makes finding the position of a missing "end" extremely easy. ---------------------------------------------------------------------- Otto · 2020-03-19 09:23 Hello everyone I also always use outline features, but sometimes they are not enough. @soerensen3 I got an error while compiling, I will send you a message with details as soon as possible. Unfortunately these days I had little time to investigate the cause of the problem, I only tried to compile on Windows 10 64bit In Lazarus- Trunk, FPC 3.0.4 and 3.3.1. Coming soon I will update FPC and I will also try it on Linux (usually I use Manjaro Linux). Otto. ---------------------------------------------------------------------- PascalDragon · 2020-03-19 09:36 Quote from: mercurhyo on March 18, 2020, 01:32:44 pmQuote from: Otto on March 18, 2020, 12:17:54 pmI will respond in separate posts to reduce the risk of confusion. @mercurhyo Thank you mercurhyo. That is exactly what I was referring to. This "SMARTLINK" feature should certainly be used to implement the theoretical concept of PartialUnits. In essence, the idea of PartialUnits would be nothing more than the concept of "Divide et impera" applied to a single Unit while always maintaining an OOP-type approach. I would have a question: What is the "MyUnit.thisfunction;" syntax used by Delphi called? Looks a lot like the syntax that is used in C# (.Net in geneneral) to access the sub-Classes. Unfortunately, at the moment, SMARTLINK only works on applications (standalone executables) it does not work on libraries that you create. it's explained somewhere on the wiki, and it is due to compiler limitations (the compiler do not work with an artificial intellig. neuronal). SO it is stable!!! and SAFE! Ehm... smartlinking also works for libraries. Everything that is exported from a library is considered "referenced" (just like an executable's entry point is considered "referenced") and everything that is referenced by a "referenced" function is considered "referenced" as well, thus it's in your hand what gets linked in. Quote from: mercurhyo on March 18, 2020, 01:32:44 pm.... maybe one day, with dynamic packages instead of static, let say, around 2030 Dynamic packages will solve nothing there. In that regard they are even worse, because all interface-sections of all units are considered exported and thus "used". A package will contain all code for its contained units (except private functions that are not used). The main advantage here is that packages can be used by multiple applications and thus the required storage space in total can be reduced. For only one application the required space will be larger however (see also this mail where I demonstrated the sizes). ---------------------------------------------------------------------- mercurhyo · 2020-03-19 10:01 Quote from: PascalDragon on March 19, 2020, 10:36:20 am Ehm... smartlinking also works for libraries. Everything that is exported from a library is considered "referenced" (just like an executable's entry point is considered "referenced") and everything that is referenced by a "referenced" function is considered "referenced" as well, thus it's in your hand what gets linked in. rhaaaa DEF NO! what would happen if one of the caller executableS run some code in a Lib that the SmartLinker have eliminated. Feel free to buy a brain, friend, or search into the wiki... as i said , it is explained somewhere on it ---------------------------------------------------------------------- marcov · 2020-03-19 10:07 Quote from: wp on March 19, 2020, 10:12:38 amQuote from: soerensen3 on March 19, 2020, 09:40:32 amAlso there is the outline feature if you use Lazarus: https://wiki.freepascal.org/Lazarus_IDE_Tools#Outline +1 This feature was a bit distracting in the beginning because of the many colors. But once I got used to it, I use it every day. It makes finding the position of a missing "end" extremely easy. I had to do some minor verilog work to customize a (FPGA based) device, which was a 20 level nested if. Verilog uses keywords similar to Pascal. Martin helped me configuring outline, and then I hacked the IDE so it the verilog code was colored, which was a great help. ---------------------------------------------------------------------- marcov · 2020-03-19 10:08 Quote from: mercurhyo on March 19, 2020, 11:01:22 amQuote from: PascalDragon on March 19, 2020, 10:36:20 am Ehm... smartlinking also works for libraries. Everything that is exported from a library is considered "referenced" (just like an executable's entry point is considered "referenced") and everything that is referenced by a "referenced" function is considered "referenced" as well, thus it's in your hand what gets linked in. rhaaaa DEF NO! what would happen if one of the caller executableS run some code in a Lib that the SmartLinker have eliminated. Feel free to buy a brain, friend, or search into the wiki... as i said , it is explained somewhere on it It can only call exported functions, and those are linked in as PascalDragon says. ---------------------------------------------------------------------- mercurhyo · 2020-03-19 10:13 @Marcov I thrust better the wiki than any forum. It awlays brought me luck and I spared a lot of time this way. So if the wiki is wrong, someone have to correct it. ---------------------------------------------------------------------- PascalDragon · 2020-03-19 14:48 Quote from: mercurhyo on March 19, 2020, 11:01:22 amQuote from: PascalDragon on March 19, 2020, 10:36:20 am Ehm... smartlinking also works for libraries. Everything that is exported from a library is considered "referenced" (just like an executable's entry point is considered "referenced") and everything that is referenced by a "referenced" function is considered "referenced" as well, thus it's in your hand what gets linked in. rhaaaa DEF NO! what would happen if one of the caller executableS run some code in a Lib that the SmartLinker have eliminated. You are aware that I'm one of the compiler developers? That I'm also the one developing FPC's dynamic package implementation? Thus I do know what I'm talking about. This is how smartlinking works: an executable (or another library) can only call functions of a library that are exported from said library (this is ensured by the operating system). For smartlinking the linker simply needs to build the transitive hull of all function and data that is accessed from the exported functions (and transitive means that if function A references function B and B in turn references function C that means that A also references C). Anything else can not be accessed by outside code. This is the same approach that is used for executables. Quote from: mercurhyo on March 19, 2020, 11:01:22 amFeel free to buy a brain, friend, or search into the wiki... as i said , it is explained somewhere on it The wiki can be edited by anyone so that information needs to be taken with a grain of salt. ---------------------------------------------------------------------- dsiders · 2020-03-19 15:03 Quote from: mercurhyo on March 19, 2020, 11:01:22 amrhaaaa DEF NO! what would happen if one of the caller executableS run some code in a Lib that the SmartLinker have eliminated. Feel free to buy a brain, friend, or search into the wiki... as i said , it is explained somewhere on it For the want of a "Bozo" filter another forum is stained... Or at least be more selective about who you engage in a pissing contest. ---------------------------------------------------------------------- Otto · 2020-03-19 17:29 I really hope not, especially now that the conversation had taken the right direction. After all, I think mercurhyo was joking or that in his home area his was an idiomatic phrase. For example, in Italian to wish good luck it is often said "In bocca al lupo!" (→"Good luck!") that saying in full would be “Vorrei che tu finissi in bocca al lupo!” that literally translated would "I wish you'd end up in the wolf's mouth!" with an obvious different meaning. Otto. ---------------------------------------------------------------------- PascalDragon · 2020-03-20 08:34 Quote from: dsiders on March 19, 2020, 04:03:18 pmOr at least be more selective about who you engage in a pissing contest. ---------------------------------------------------------------------- Otto · 2020-03-20 09:08 @soerensen3 Thank you for adapting your project pasunitmerge so that it can work on Windows 10 64bit. Otto. ---------------------------------------------------------------------- Otto · 2020-03-20 10:23 Hello everyone. I adapted my "do-nothing example" so that it could work with the soerensen3 project. It is not yet a strict version, there are changes to be made so that it can be considered suitable to meet the version of the OOP implementation commonly used in FPC. I repeat that the example is for the sole purpose of discussing the usefulness of PartialUnits. As surely already understood by all, it refers to a way to replicate the implementation, including the logic used to position the events declaration, which Lazarus uses in the RAD. Starting with two separate PartialUnits: "PUnitMain_COD.pp" and "PUnitMain_LFM.pp", which respectively correspond to the part dedicated to the code and the part dedicated to the GUI (the .lfm file) we get the file "UnitMain.pas" which is compilable with the FPC without making any further changes. This is possible by running the soerensen3 program with the following parameters: Code: Bash  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i pasunitmerge PUnitMain_COD.pp PUnitMain_LFM.pp -o UnitMain.pas "PUnitMain_COD.pp" Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit unitMain;    // PseudoPartial_unitMain     {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls; type   { TForm1 }   TForm1 = class(TForm)    BtnClose: TButton;    Panel1: TPanel;    procedure BtnCloseClick(Sender: TObject);    procedure FormCreate(Sender: TObject);  // PseudoPartial_FormCreate    procedure InitializeLayaut(Sender: TObject); (* forward; *)// PseudoPartial_FormCreate  private   public   end; var  Form1: TForm1; implementation     {$R *.lfm} { TForm1 } procedure TForm1.BtnCloseClick(Sender: TObject);begin  Close;end; procedure TForm1.FormCreate(Sender: TObject);   // PseudoPartial_FormCreatebegin  Form1.InitializeLayaut(self);   // PseudoPartial_InitializeLayautend;     // PseudoPartial_FormCreate end.     // PseudoPartial_unitMain     "PUnitMain_LFM.pp" Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit unitMain;        // PseudoPartial_unitMain     {$mode objfpc}{$H+} interface uses  Controls; (*type   { TForm1 }   TForm1 = class(TForm)    procedure InitializeLayaut(Sender: TObject);  // PseudoPartial_FormCreate  private   public   end; *) // var implementation { TForm1 } procedure TForm1.InitializeLayaut(Sender: TObject);// PseudoPartial_InitializeLayautbegin   // Component serialized as Pascal - Begin  // Format version 1  Name := 'Form1';  Panel1 := TPanel.Create(Self);  BtnClose := TButton.Create(Self);  Left := 338;  Height := 512;  Top := 137;  Width := 512;  BorderStyle := bsNone;  Caption := 'Form1';  ClientHeight := 512;  ClientWidth := 512;  OnCreate := @FormCreate;  Position := poDesktopCenter;  LCLVersion := '2.0.6.0';  with Panel1 do  begin    Name := 'Panel1';    Left := 0;  Height := 512;    Top := 0;    Width := 512;    Anchors := [akTop..akBottom];    ClientHeight := 512;    ClientWidth := 512;    Color := clOlive;    ParentColor := False;    TabOrder := 0;    Parent := Self;    with BtnClose do    begin      Name := 'BtnClose';      Left := 432;      Height := 25;      Top := 8;      Width := 75;      Caption := 'Close';      OnClick := @BtnCloseClick;      TabOrder := 0;      Parent := Panel1;    end;  end;  // Component serialized as Pascal - End end;  // PseudoPartial_InitializeLayaut end.  // PseudoPartial_unitMain  "UnitMain.pas" Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit UnitMain; interface uses  Classes,  Controls,  Dialogs,  ExtCtrls,  Forms,  Graphics,  StdCtrls,  SysUtils; // UnitMain_COD -->type   { TForm1 }   TForm1 = class(TForm)    BtnClose: TButton;    Panel1: TPanel;    procedure BtnCloseClick(Sender: TObject);    procedure FormCreate(Sender: TObject);  // PseudoPartial_FormCreate    procedure InitializeLayaut(Sender: TObject); (* forward; *) // PseudoPartial_FormCreate  private   public   end; var  Form1: TForm1;// <--UnitMain_COD // UnitMain_LFM -->(*type   { TForm1 }   TForm1 = class(TForm)    procedure InitializeLayaut(Sender: TObject);  // PseudoPartial_FormCreate  private   public   end; *) // var// <--UnitMain_LFM implementation // UnitMain_COD -->procedure TForm1.BtnCloseClick(Sender: TObject);begin  Close;end; procedure TForm1.FormCreate(Sender: TObject);   // PseudoPartial_FormCreatebegin  Form1.InitializeLayaut(self);   // PseudoPartial_InitializeLayautend;     // PseudoPartial_FormCreate// <--UnitMain_COD // UnitMain_LFM -->procedure TForm1.InitializeLayaut(Sender: TObject);// PseudoPartial_InitializeLayautbegin   // Component serialized as Pascal - Begin  // Format version 1  Name := 'Form1';  Panel1 := TPanel.Create(Self);  BtnClose := TButton.Create(Self);  Left := 338;  Height := 512;  Top := 137;  Width := 512;  BorderStyle := bsNone;  Caption := 'Form1';  ClientHeight := 512;  ClientWidth := 512;  OnCreate := @FormCreate;  Position := poDesktopCenter;  LCLVersion := '2.0.6.0';  with Panel1 do  begin    Name := 'Panel1';    Left := 0;  Height := 512;    Top := 0;    Width := 512;    Anchors := [akTop..akBottom];    ClientHeight := 512;    ClientWidth := 512;    Color := clOlive;    ParentColor := False;    TabOrder := 0;    Parent := Self;    with BtnClose do    begin      Name := 'BtnClose';      Left := 432;      Height := 25;      Top := 8;      Width := 75;      Caption := 'Close';      OnClick := @BtnCloseClick;      TabOrder := 0;      Parent := Panel1;    end;  end;  // Component serialized as Pascal - End end;  // PseudoPartial_InitializeLayaut// <--UnitMain_LFM end.  I hope that I have explained myself in an understandable way and that I have not made any serious mistakes during the translation. Any opinion or criticism, even in languages other than English, is well accepted. Otto. ---------------------------------------------------------------------- ASBzone · 2020-03-23 15:06 Quote from: winni on March 19, 2020, 12:29:40 amHi! I do it the simpler way since I returned from Modula2 to Pascal: Whenever I write a "begin" I add at once after the "end" the reason. So the last lines of a procedure look like:      end; // if <> transparent   end; // for x  end; // for y end; // proc Winni There is much wisdom in this. I used to do this at one time (a long time ago), and stopped.   I should pick it back up again. ---------------------------------------------------------------------- ASBzone · 2020-03-23 15:12 Quote from: soerensen3 on March 19, 2020, 09:40:32 amAlso there is the outline feature if you use Lazarus: https://wiki.freepascal.org/Lazarus_IDE_Tools#Outline Nice!! I really have to take some time and dig through all the options... ---------------------------------------------------------------------- kupferstecher · 2020-03-24 12:35 Quote from: Otto on March 20, 2020, 11:23:44 amStarting with two separate PartialUnits: "PUnitMain_COD.pp" and "PUnitMain_LFM.pp", which respectively correspond to the part dedicated to the code and the part dedicated to the GUI (the .lfm file) we get the file "UnitMain.pas" which is compilable with the FPC without making any further changes. This is possible by running the soerensen3 program with the following parameters: I'm not sure what is your final target, but if you use a seperate program to merge split units, you probably get trouble with code navigation and code completion in the IDE. What I could think about of being a useful feature is that a Class could be declared as 'friend' with an other class which would allow to access e.g. protected fields of that other class directly. With this feature two units could be linearly entangled (which imho is ok) and still the encapsulation to outside units would be kept, as only public declarations are accessible to third units. But this would mean additional complexitivity to the language, I'm not sure if it would be worth it. Hypothetical Example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type TFoo = class(friends TThread)  Procedure DoSomething;end; IMPLEMENTATION Procedure DoSomethingbegin  MyBusyThread.Synchronize(@SthElse);  //Synchronize is a protected procedure, thus it wouldn't be accessible here*end; * Yes, it's not the best example as there is a public version of Synchronize... ---------------------------------------------------------------------- Otto · 2020-03-25 16:01 Thank you kupferstecher for your response. I am very pleased to know that there are other developers interested in this topic. Quote from: kupferstecher on March 24, 2020, 01:35:19 pmif you use a seperate program to merge split units, you probably get trouble with code navigation and code completion in the IDE. At the moment what you say is very likely; but I'm trying to increase feature integration with Lazarus-IDE.  QuoteWhat I could think about of being a useful feature is that a Class could be declared as 'friend' with an other class which would allow to access e.g. protected fields of that other class directly. With this feature two units could be linearly entangled (which imho is ok) and still the encapsulation to outside units would be kept, as only public declarations are accessible to third units. But this would mean additional complexitivity to the language, I'm not sure if it would be worth it. Your proposal looks very interesting; from an initial evaluation I think can be integrated into the abstract concept of PartialUnit. After studying and thinking more, I will ask you for more details. QuoteI'm not sure what is your final target At this stage, the ultimate purpose of the project is still very difficult to describe, I have yet to prepare a clear and organic speech. Generally speaking, what I would like to achieve is facilitation in the introduction of new features into the Lazarus- IDE/FPC programming environment avoiding, where possible, compiler changes. Implementing PartialUnits might e.g. help when converting code from other programming languages. It would be possible to deal separately with the different implementations of OOP (or other programming paradigms) that are unique to each programming language. A hint of what I'm saying is present in the code I reported in my previous post. In particular, we could use this method to replace the file "Lazarus Form" (.lfm file) with Pascal Object code. The various declarations and implementations of the code could be distributed in accordance with the preferred OOP logic: in fact, the PartialUnits, in my opinion, are not to be considered separate Units, but a single unit deployed in different blocks of code. As you can see from the example, both have the same name as "unitMain". I have not yet adapted the merging code (pasunitmerge) to be able to respect the distribution of the code to my liking e.g. the definition of the InitializeLayaut method would go all over in the file "PunitMain_LFM.pp", for now I have only added the part of the code  commented on). There are components that are used to convert the "Lazarus Form files" into Pascal code (in this thread I learned how to use it thanks to wp). For now they do not do the job completely automatically, but they could be refined and adapted to produce a reversible conversion (from pascal code to lfm script and vice versa). The advantage would not be to be underestimated, you could edit complex GUIs directly in pascal code and have the ".lfm" file regenerated for Lazarus. Also I think (I haven't checked yet and so the probability that I'm wrong is very high) that the compiler still needs a pre-conversion from ".lfm files" to pascal code before FPC can compile the project. I believe that what I have said is achievable without having to make significant changes to the Lazarus-IDE. (-: Thank you for having the patience to read my post. :-) Otto. ---------------------------------------------------------------------- kupferstecher · 2020-03-25 22:46 Hello Otto, Quote from: Otto on March 25, 2020, 05:01:02 pmAt the moment what you say is very likely; but I'm trying to increase feature integration with Lazarus-IDE.If you have split units that represent one unit then you can access all variables which are in the other part of the split unit. So the codetools have to recognise both units as one, as well. I have no insight to that, but i guess it's quite difficult to achive, even more if you can't include it as standard installation. The debugger would be an other topic. -- Another idea: Use the include file as basis and add IDE features so that the include file is recognised and shown as part of the whole unit. If the include file is recognized, you could also show e.g. the interface part in the editor window of the included file. The advantage would be that you don't need further utilities, preprocessor etc. It would be just a different way of displaying the files. But no idea how to implement something like that. -- A (compiler) feature that i miss is a forwarding mechanism of units in "uses". So that a library can consist of several units and the library's main unit begins like that Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit MyLib;publishes MyLibPart1,MyLibPart2,MyLibPart3;Then when using the library it would be enough to write Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses MyLib;and all forwarded units would be implicitly used/accessible. But probably there are reasons for not having that :-) ---------------------------------------------------------------------- Otto · 2020-03-26 16:57 Hi kupferstecher. Quote from: kupferstecher on March 25, 2020, 11:46:13 pmIf you have split units that represent one unit then you can access all variables which are in the other part of the split unit. So the codetools have to recognise both units as one, as well. I have no insight to that, but i guess it's quite difficult to achive, even more if you can't include it as standard installation. The debugger would be an other topic. In fact, this is a very complex problem to solve. At this early stage I was considering using an external component that can store links between the WholeUnit and the various PartialUnits. The debugger might also work with this system. In practice, for FPC and Lazarus everything would remain the same, but the developer could use the PartialUnits that would remain synchronized with WholeUnit. QuoteAnother idea: Use the include file as basis and add IDE features so that the include file is recognised and shown as part of the whole unit. If the include file is recognized, you could also show e.g. the interface part in the editor window of the included file. The advantage would be that you don't need further utilities, preprocessor etc. It would be just a different way of displaying the files. But no idea how to implement something like that.It is possible that using the include directive correctly can improve the linking phase. But I have to admit that I'm not sure I fully understood your idea.  QuoteA (compiler) feature that i miss is a forwarding mechanism of units in "uses". Forwarding mechanism must, in some way, certainly be used to enable the implementation of PartialUnits. Thank you very much for your interest. Discussing with other programmers is always very helpful and helps to evaluate further possibilities. Otto. ---------------------------------------------------------------------- kupferstecher · 2020-03-26 18:07 Quote from: Otto on March 26, 2020, 05:57:34 pmQuoteAnother idea: Use the include file as basis and add IDE features so that the include file is recognised and shown as part of the whole unit. If the include file is recognized, you could also show e.g. the interface part in the editor window of the included file. The advantage would be that you don't need further utilities, preprocessor etc. It would be just a different way of displaying the files. But no idea how to implement something like that.[...] I'm not sure I fully understood your idea. The idea was to use what the language provides, i.e. the include files and display them like your partial units. The IDE already can handle include files very well, with code completion and so on. You could change the way of displaying the include file like I tried to show below. Example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit unitMain;interfaceuses  Classes, SysUtils type TForm1 = class(TForm)  procedure FormCreate(Sender: TObject);     procedure InitializeLayout(Sender: TObject);  //Part of the include  end; implementation{$I unitMain_subpart.inc}  //here the content of the "partial unit", i.e. of the include file, could be shown by code folding in a grayed out, readonly way. procedure TForm1.FormCreate(Sender: TObject); begin  Form1.InitializeLayout(self);end; end. unitMain_subpart.inc Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i (*unit unitMain;   //Here the header could be included in grayed out, read- only way.interfaceuses  Classes, SysUtils type TForm1 = class(TForm)  procedure FormCreate(Sender: TObject); procedure InitializeLayout(Sender: TObject);  end; implementation *) procedure TForm1.InitializeLayout(Sender: TObject);begin  ...end; ---------------------------------------------------------------------- Otto · 2020-03-26 20:58 Hi kupferstecher. Quote from: kupferstecher on March 26, 2020, 07:07:46 pmThe idea was to use what the language provides, i.e. the include files and display them like your partial units. The IDE already can handle include files very well, with code completion and so on. [...] Great tip. I started the thread using the {$include …} directives. The fact that with the includes directives it is so easy to navigate within the code denotes how well Lazarus is done. In the post #23 I had reported an example just to explain what I wanted to achieve without altering anything in FPC, reporting the code not yet acceptable commented. The suggestion leads me to believe that the feasibility of the abstract concept of PartialUnits is closer. In fact, instead of creating a synchronizer for PartialUnits and the Unit-Integer, I could only create a converter between PartialUnits and IncludeFiles (code blocks linked by the use of $include directives). The work would be considerably simpler and certainly at an early stage even easier to describe. Later, if we wanted to integrate into the IDE or an external component, it could always be adapted to future needs. These days I will try to write a descriptive text in order to evaluate the possibility of creating an open source project. However, I don't have much experience in open source projects. Thanks again kupferstecher. Otto. ---------------------------------------------------------------------- soerensen3 · 2020-03-27 22:10 How about this skeleton: Unit1.Partial1: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {%region /fold}{$IFNDEF INCLUDE}{%endregion} unit Unit1.Partial1; {$mode objfpc}{$H+} interface uses  Classes,  SysUtils; {%region /fold}{$DEFINE INCLUDE_INTF}{$ENDIF} {$IFDEF INCLUDE_INTF}{%endregion} // interface here {%region /fold}{$ENDIF}{$IFNDEF INCLUDE}{%endregion} implementation {%region /fold}{$DEFINE INCLUDE_IMPL}{$ENDIF}{$IFDEF INCLUDE_IMPL}{%endregion} // implementation here{%region /fold}{$ENDIF}{$IFNDEF INCLUDE}{%endregion}end. {%region /fold}{$ENDIF}{%endregion} Unit1: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils,  fpjson,  Math,  LazUTF8,  LazFileUtils; {$DEFINE INCLUDE}{$DEFINE INCLUDE_INTF}{$INCLUDE Unit1.lib.inc}{$UNDEF INCLUDE}{$UNDEF INCLUDE_INTF} implementation {$DEFINE INCLUDE}{$DEFINE INCLUDE_IMPL}{$INCLUDE Unit1.lib.inc}{$UNDEF INCLUDE}{$UNDEF INCLUDE_IMPL} end. Unit1.lib.inc: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$INCLUDE Unit1.Partial1.pas}//add other partial units here It will work as a normal unit but if you want to merge it you just put Unit1 in the uses section. If you need forward declarations across files then of course you can't use the partial unit in a uses section. It does not break code completion completely however if you work with the partial unit. ---------------------------------------------------------------------- Otto · 2020-03-28 20:23 Thank you soerensen3. I'm checking to see if I can use your suggestion, I'll let you know. Otto. ---------------------------------------------------------------------- Otto · 2020-03-29 16:01 Hello everyone. Good news, the suggestion of soerensen3 proved very useful. I prepared a simple example based on the skeleton proposed by soerensen3, to see if implementing the abstract concept of PartialUnit kept the essential features of the Lazarus-IDE editor. The result was positive. The code completion is working, the navigation in the code works correctly. The Code Explorer correctly displays the PartialUnits as if it were a single Unit and allows for proper and fast navigation. I would like to mention that the PartialUnit is defined as: a single unit fragmented into separate parts of code. Warning: The following code is intended to verify that code completion works when using Units deployed in different files. It is not intended to be useful for different purposes. expu_main.pasCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit ExPU_Main; {$mode objfpc}{$H+} interface uses  Classes, SysUtils,  fpjson,  //Math,  //LazUTF8,  LazFileUtils; {%region Interface_PartialUnit}{$DEFINE INCLUDE}{$DEFINE INCLUDE_INTF}{$INCLUDE ExPU.lib.inc}{$UNDEF INCLUDE}{$UNDEF INCLUDE_INTF}{%endregion} OpR = Class(TObject)  Private  public    class Function Aum(iVar, iTo:integer): integer;  static;    class Function Dim(iVar:integer; iTo:integer): integer;  static;    class Function Mul(iVar:integer; iTo:integer): integer;  static;  end; var  a : integer = 5; implementation {%region Implementation_PartialUnit}{$DEFINE INCLUDE}{$DEFINE INCLUDE_IMPL}{$INCLUDE ExPU.lib.inc}{$UNDEF INCLUDE}{$UNDEF INCLUDE_IMPL}{%endregion} { Opex } class function Opex.Dim(iVar:integer):integer;begin  result := iVar-1;end; { OpR } class Function OpR.Mul(iVar:integer; iTo:integer): integer;begin  result := iVar*iTo;end; end.                   ExPU.Partial1.pasCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {%region PartialUnit_Begin}{$IFNDEF INCLUDE}{%endregion} unit ExPU.Partial1; {$mode objfpc}{$H+} interface uses  Classes,  SysUtils; {%region interface_Begin}{$DEFINE INCLUDE_INTF}{$ENDIF} {$IFDEF INCLUDE_INTF}{%endregion} // interface hereType  Opex = Class(TObject)  Private    //class var myprivatea : integer;  public    //class Function GetA : Integer;  static;    //class Procedure SetA(AValue : Integer); static;    //function Aumenta(iVar:integer):integer;    class Function Aum(iVar:integer): integer;  static;    class Function Dim(iVar:integer): integer;  static;  end; {%region interface_End}{$ENDIF}{$IFNDEF INCLUDE}{%endregion} implementation {%region implementation_Begin}{$DEFINE INCLUDE_IMPL}{$ENDIF}{$IFDEF INCLUDE_IMPL}{%endregion}// implementation here function Aum(iVar:integer):integer;begin  result := iVar+1;end; { Opex } class function Opex.Aum(iVar:integer):integer;begin  //result:=Aum(iVar); //  result := iVar+1;end; { OpR } class Function OpR.Aum(iVar:integer; iTo:integer): integer;begin  result:=iVar+iTo;end; class Function OpR.Dim(iVar, iTo:integer): integer;begin  result:=iVar- iTo;end; {%region implementation_End}{$ENDIF}{$IFNDEF INCLUDE}{%endregion} end. {%region PartialUnit_End}{$ENDIF}{%endregion}  expu.costanti.pas Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {%region PartialUnit_Begin}{$IFNDEF INCLUDE}{%endregion} unit expu.costanti;    // test Name {$mode objfpc}{$H+} interface uses  Classes,  SysUtils; {%region interface_Begin}{$DEFINE INCLUDE_INTF}{$ENDIF}{$IFDEF INCLUDE_INTF}{%endregion} // interface hereType  Costanti = Class(TObject)  Private  public    const Val1:byte=$0A;          Val2:byte=42;          Val3:byte=13;  end; {%region interface_End}{$ENDIF}{$IFNDEF INCLUDE}{%endregion} implementation {%region implementation_Begin}{$DEFINE INCLUDE_IMPL}{$ENDIF}{$IFDEF INCLUDE_IMPL}{%endregion}// implementation here{%region implementation_End}{$ENDIF}{$IFNDEF INCLUDE}{%endregion} end.{%region PartialUnit_End}{$ENDIF}{%endregion}  Now the possibility of obtaining PartialUnits is more concrete. Thanks again soerensen3 and kupferstecher. Otto.