Lazarus

Programming => General => Topic started by: jollytall on November 05, 2021, 03:50:50 pm

Title: OOP structures in fpc and Lazarus
Post by: jollytall on November 05, 2021, 03:50:50 pm
I read a lot the documentation, this forum and made my own experiences with various OOP structures, like advanced records, objects, classes. Over time I gathered a lot of information, and put it all in one document originally for myself, but now I share it hereby.
It is rather long, but I tried to cover everything that caused a problem to me and what was not obvious to find in the documentations.
I am glad if I can help anyone with it, and also would be very thankful to those who know more about these topics and take the time to read it and provide feedback.
Please feel free to write any error you find, any comment you have or any topic that should be added.
For the time being it will be here, so if you want to share, please distribute this link rather than a copy of the document. I expect it to be updated, so a copy is a dead-end with a half ready document.

P.S. It was written as.odt originally (55Kb), but it could not be attached, so I saved as .docx (47Kb). Neither could upload that. Tried to save as .doc or .pdf (250Kb) and even renaming the smaller .docx to .doc, but none of them worked. For the three latter cases the form to Post simply did nothing. Any idea, what can be wrong?
Title: Re: OOP structures in fpc and Lazarus
Post by: MarkMLl on November 05, 2021, 03:56:00 pm
Try putting it in a pdf and zipping it.

MarkMLl
Title: Re: OOP structures in fpc and Lazarus
Post by: skalogryz on November 05, 2021, 04:02:55 pm
Any idea, what can be wrong?
I'm sorry. but your approach to distributing the techy information in 21st century is wrong.

Don't make people download your file and read it.
Instead you need to write up the article on some online blogging platform and share the link.
(And Google will be your friend, in terms - your article will become the part of the "search results" for Pascal and OOP)

You can write the same article on the Freepascal wiki, yet this might undermine your authorship of the content. (as wiki page is intended to be multiauthor)

If you really want to go old-school, you might want to write a book about pascal.
But sharing the book on the forum... is good as dead.  Sure... 5 people will download and maybe even read it. But that's it.
Don't let your effort to get wasted - go public! go online!
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 05, 2021, 04:14:49 pm
It is a shame, the zip-ed pdf is still 220 Kb.
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 05, 2021, 04:17:30 pm
I'm sorry. but your approach to distributing the techy information in 21st century is wrong.

You are right, but...
I see that in this community there are always people who are willing to help, correct, etc.
If once it goes through the validation, I am happy to share it in any form, wiki, whatever; I do not have copyright concerns.
Title: Re: OOP structures in fpc and Lazarus
Post by: BobDog on November 05, 2021, 04:26:23 pm

"OOP structures in fpc and Lazarus"
I like the OOP in fpc, I haven't posted much OOP, but I am working away in the background.
But not being a Lazarus ide user (very much), is there a difference in OOP between the two?
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 05, 2021, 05:13:37 pm
Not really. Lazarus is just an IDE for FPC.
The only difference, (what is not yet included in my doc), that Lazarus has a whole set of classes defined for visual access, but they are start from TObject, then TPersistent and TComponent. Those can also be accessed from a plain source, but the great benefit of Lazarus that you can design your visuals WYSIWYG. Actually there are many other non-visual components, what I am not too keen on (anything from networking to database, etc.), but there I personally prefer programming them the normal way.
Title: Re: OOP structures in fpc and Lazarus
Post by: ccrause on November 05, 2021, 05:24:04 pm

"OOP structures in fpc and Lazarus"
I like the OOP in fpc, I haven't posted much OOP, but I am working away in the background.
But not being a Lazarus ide user (very much), is there a difference in OOP between the two?
Lazarus also uses fpc as the compiler, so it is not necessary to mention Lazarus when discussing language features (IMHO). 

Lazarus does provide a lot of editorial help that makes it easier and faster to create and maintain classes (and objects, advanced records...) e.g. by creating empty methods in the implementation section that corresponds to methods declared in a class, synchronization of parameters between interface and implementation and so forth.

Edit: I see @jollytall was a bit quicker to post...
Title: Re: OOP structures in fpc and Lazarus
Post by: Lulu on November 05, 2021, 08:55:22 pm
@jollytall: thanks You to share ! :)
Title: Re: OOP structures in fpc and Lazarus
Post by: MarkMLl on November 05, 2021, 10:01:20 pm
It is a shame, the zip-ed pdf is still 220 Kb.

Yes, because AIUI PDF is basically compressed Postscript.

I'm working through it with interest, but noting your overall approach you might find http://web.engr.oregonstate.edu/~budd/Books/leda/ of interest.

MarkMLl
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 10, 2021, 04:20:50 pm
Well, not many comments yet, so I try to ask some of the questions raised in the document, explicitly here:
Q1. Mode and Modeswitch for advanced records
I analyzed and wrote that it is a bit tricky what mode to use to be able to use advanced records.
- In Mode delphi everything (instance and class level fields and methods) is possible, no need of modeswitch advancedrecords.
- In Mode objfpc also everything is possible, but advancedrecords is also needed.
- In Mode fpc even with advancedrecords, only the instance level fields and methods are available, class level is not possible.
What is the logic of this set-up? Why are objfpc and advancedrecords sort of independent, and not one including the other (either way)?
Title: Re: OOP structures in fpc and Lazarus
Post by: cdbc on November 10, 2021, 06:37:53 pm
Hi
Short answer:
0)  Get a Github account - It's free.
1)  Create a repository for your document.
2)  Share the link to repo here, easy peasy  ;)
Good luck.
Regards Benny
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 10, 2021, 07:43:10 pm
Thanks,
As said above, the plan is to share it once the questions, problems are corrected, but I trust this community most to validate and answer the uncertainties I have.

(and I have a github account, but that does not answer my questions  :))
Title: Re: OOP structures in fpc and Lazarus
Post by: MarkMLl on November 10, 2021, 08:14:57 pm
If it ain't broke, don't fix it.

So why the Hell should we all be obliged to do absolutely everything via Github or equivalent these days?

He didn't ask about a way to publish his document. He asked about a way of making it available to other members of this forum for review and constructive criticism.

MarkMLl
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 10, 2021, 09:45:07 pm
MarkMLI I think is right, but that is not the point. So, before it turns into a religious war, I ask my second question (and still hope, someone can shed some light on Q1).

Q2. Why is there a static keyword needed for an advanced record class level method?
The good news is that it is at least coherent with the object approach, i.e. a class procedure X; static; can be called with the type tTest.X and there is no Self available.
On the other hand I do not understand why is it implemented this way. To me two ways would be logic:
EITHER
it would be similar to object, but then why not to allow class procedure X; (without static) and procedure X; static; (without class) with slightly different behavior?
OR
accept the fact that record is different than object and in record there is only one way to make a method class level, but then why need to use static at all? Using only class procedure X; would be in line with the record field declaration where there is only one way to define with class var (unlike the object where static is also allowed to define a field, but that is another question).
Title: Re: OOP structures in fpc and Lazarus
Post by: ArtLogi on November 10, 2021, 09:52:16 pm

"OOP structures in fpc and Lazarus"
I like the OOP in fpc, I haven't posted much OOP, but I am working away in the background.
But not being a Lazarus ide user (very much), is there a difference in OOP between the two?
Lazarus also uses fpc as the compiler, so it is not necessary to mention Lazarus when discussing language features (IMHO). 

Lazarus does provide a lot of editorial help that makes it easier and faster to create and maintain classes (and objects, advanced records...) e.g. by creating empty methods in the implementation section that corresponds to methods declared in a class, synchronization of parameters between interface and implementation and so forth.

Edit: I see @jollytall was a bit quicker to post...
Even though I'm total noob, there is compiler directive to lazarus (FPC____) vs FPC, which kind of makes it kind of also if not language feature, at least local dialect.

Thank you for the learning resorce I will read it.
Title: Re: OOP structures in fpc and Lazarus
Post by: PascalDragon on November 11, 2021, 09:16:14 am
Even though I'm total noob, there is compiler directive to lazarus (FPC____) vs FPC, which kind of makes it kind of also if not language feature, at least local dialect.

What do you mean? The $Mode directive with Lazarus setting it to ObjFPC by default? That has nothing to do with Lazarus, but it's a functionality of FPC to allow different language modes per unit (the main ones are ObjFPC and Delphi). In the default mode most Object Pascal related functionality is disabled (e.g. classes).

MarkMLI I think is right, but that is not the point. So, before it turns into a religious war, I ask my second question (and still hope, someone can shed some light on Q1).

Q2. Why is there a static keyword needed for an advanced record class level method?
The good news is that it is at least coherent with the object approach, i.e. a class procedure X; static; can be called with the type tTest.X and there is no Self available.
On the other hand I do not understand why is it implemented this way. To me two ways would be logic:
EITHER
it would be similar to object, but then why not to allow class procedure X; (without static) and procedure X; static; (without class) with slightly different behavior?
OR
accept the fact that record is different than object and in record there is only one way to make a method class level, but then why need to use static at all? Using only class procedure X; would be in line with the record field declaration where there is only one way to define with class var (unlike the object where static is also allowed to define a field, but that is another question).

Short answer: because that's how Delphi did it.

Long answer: Delphi used the same syntax that is used for static methods inside classes also for records. In classes you either have a class method using class procedure or class function (which takes the class type as Self parameter and can also be virtual) or a static class method if you append the static modifier (in which case there is no Self). Now, Delphi doesn't really acknowledge object at all (considering it deprecated and such) and thus they simply used the syntax they know to also implement it for records when they implemented advanced records.
By the way: the correct syntax in an object declaration is without the class keyword, but with the static modifier. That is because the object type stems from a time before classes were introduced, thus also before the introduction of the class keyword. FPC also allows the syntax from the class type simply because both objects and classes share a lot of code and sometimes objects gain functionality introduced for classes simply by accident.
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 11, 2021, 01:21:52 pm
Short answer: because that's how Delphi did it.

Long answer: Delphi used the same syntax that is used for static methods inside classes also for records. In classes you either have a class method using class procedure or class function (which takes the class type as Self parameter and can also be virtual) or a static class method if you append the static modifier (in which case there is no Self). Now, Delphi doesn't really acknowledge object at all (considering it deprecated and such) and thus they simply used the syntax they know to also implement it for records when they implemented advanced records.
By the way: the correct syntax in an object declaration is without the class keyword, but with the static modifier. That is because the object type stems from a time before classes were introduced, thus also before the introduction of the class keyword. FPC also allows the syntax from the class type simply because both objects and classes share a lot of code and sometimes objects gain functionality introduced for classes simply by accident.

Thanks PascalDragon,
although I still do not find it a complete answer.

The short answer is clear, but that would lead to two second questions:
- why did Delphi do it like this? I know it is beyond this forum to guess, but Embarcadero guys are also very smart, so surely they had either a good reason or a history behind.
- why is it the same in every mode? If you see the still open Q1 I had earlier, I feel a bit of confusion among compiler modes and modeswitches, but what is clear that different modes can accept or reject different syntax. So, even if it is the case in mode delphi, I do not see why it is still the same in mode objfpc + modeswitch advancedrecords.

From the long answer I again learnt something, that the class keyword only appeared with the class type and since object is older than class, object should not use the class procedure type definition. Btw. I use in my doc the terms "class level field, class level method", even in object. I hope it is still the correct terminology.

Also your long answer leads us to my third question:

Q3. Why does a static method in an object has Self?
I did not find any documentation for object, but I found it for class, where it states what you also write, i.e. that the static keyword makes the call without Self. It is impossible to test static alone for class, as class does not allow only static without class in front of procedure. When class procedure X; is used then it has Self, but with static; added it has not got Self. But this is almost my Q4 later, so back to object and Q3:

In object (chapter 5.3 in my doc) all the four definitions are possible (I only write procedure, but also function works the same).
Code: Pascal  [Select][+][-]
  1. procedure PNothing;
  2. procedure PStatic; static;
  3. class procedure PClass;
  4. class procedure PClassStatic; static;

The first is easy, but the other three are all some sort of class level methods. Based on the logic described above for class, I would expect that here (i.e. object) the two with the static; keyword have no Self. But it is not the case; PStatic happily has a Self, only the last one is without.
My expectation was that using the class procedure part makes it callable as tMyObject.P, while if class is not in front of it then only MyObject.P can be called, while using or not static; makes only the list of arguments different with or without Self, but it is not the case. Is it a bug?
Last, this also contradicts a bit to your answer regarding the "correct syntax". If one only uses (I am still at object!) the PStatic method from above as you suggest, then one cannot use the tMyObject.P logic, what might be handy sometimes, e.g. if we do not want to make an instance at all (equivalent of making sure that regardless how many instances are declared they all behave as the same one, i.e. only class level fields and methods are declared).

So my - might be wrong - conclusion is that for object the best is to use class procedure PClass;, for class level methods. PClass has a benefit over PStatic as it can be called from the type, while PStatic cannot AND PClass also has a benefit over PClassStatic as it always has a Self, even if we do not want to use. Is it a wrong assumption?
Title: Re: OOP structures in fpc and Lazarus
Post by: PascalDragon on November 11, 2021, 02:07:19 pm
- why did Delphi do it like this? I know it is beyond this forum to guess, but Embarcadero guys are also very smart, so surely they had either a good reason or a history behind.

I explained that in my long answer (emphasis mine):

Now, Delphi doesn't really acknowledge object at all (considering it deprecated and such) and thus they simply used the syntax they know to also implement it for records when they implemented advanced records.

- why is it the same in every mode? If you see the still open Q1 I had earlier, I feel a bit of confusion among compiler modes and modeswitches, but what is clear that different modes can accept or reject different syntax. So, even if it is the case in mode delphi, I do not see why it is still the same in mode objfpc + modeswitch advancedrecords.

Because there is no reason to change something just for the sake of changing it. Advanced records were introduced mainly for compatibility with Delphi (and they're really handy inside generics). Adding separate syntax is only done when really necessary or beneficial (e.g. introducing and using type helper for all kinds of helpers instead of abusing record helper for primitive types and who-knows-what for interface types). This is not the case for advanced records. Also any bit of additional syntax added to the compiler increases the burden when maintaining the compiler.

From the long answer I again learnt something, that the class keyword only appeared with the class type and since object is older than class, object should not use the class procedure type definition. Btw. I use in my doc the terms "class level field, class level method", even in object. I hope it is still the correct terminology.

I personally differentiate between instance and static fields/methods.

Q3. Why does a static method in an object has Self?
I did not find any documentation for object, but I found it for class, where it states what you also write, i.e. that the static keyword makes the call without Self. It is impossible to test static alone for class, as class does not allow only static without class in front of procedure. When class procedure X; is used then it has Self, but with static; added it has not got Self. But this is almost my Q4 later, so back to object and Q3:

In object (chapter 5.3 in my doc) all the four definitions are possible (I only write procedure, but also function works the same).
Code: Pascal  [Select][+][-]
  1. procedure PNothing;
  2. procedure PStatic; static;
  3. class procedure PClass;
  4. class procedure PClassStatic; static;

The first is easy, but the other three are all some sort of class level methods. Based on the logic described above for class, I would expect that here (i.e. object) the two with the static; keyword have no Self. But it is not the case; PStatic happily has a Self, only the last one is without.
My expectation was that using the class procedure part makes it callable as tMyObject.P, while if class is not in front of it then only MyObject.P can be called, while using or not static; makes only the list of arguments different with or without Self, but it is not the case. Is it a bug?
Last, this also contradicts a bit to your answer regarding the "correct syntax". If one only uses (I am still at object!) the PStatic method from above as you suggest, then one cannot use the tMyObject.P logic, what might be handy sometimes, e.g. if we do not want to make an instance at all (equivalent of making sure that regardless how many instances are declared they all behave as the same one, i.e. only class level fields and methods are declared).

So my - might be wrong - conclusion is that for object the best is to use class procedure PClass;, for class level methods. PClass has a benefit over PStatic as it can be called from the type, while PStatic cannot AND PClass also has a benefit over PClassStatic as it always has a Self, even if we do not want to use. Is it a wrong assumption?

No one said that the compiler is bug free.

The correct syntax for object is procedure Name; static. Definitely wrong is class procedure Name; (because there is no meta object type equivalent to TClass) and consequently class procedure Name; static; should be disabled as well simply because objects stem from TP times and there the class keyword was not known.
Title: Re: OOP structures in fpc and Lazarus
Post by: marcov on November 11, 2021, 04:07:35 pm
I think Pascaldragon hits the core of the issue: forget about old TP objects. Adding them into feature discussion mix only clouds the picture. These haven't seen feature expansion (other than fixing trivialities like automated types embedded in them) since TP 7 in 1994 or so, and thus were never really a factor. Delphi 2 in 1996 added classes effectuating the deprecation, now 25 years ago.

As to why that is the case, I can only speculate, but there was quite some frustration about the VMT pointer automatically appearing in TP times. From a type definition alone you can't determine if it has a VMT, you have to trace the hierarchy to find out if it declared virtual methods somewhere.

Another factor is that they might have wanted to deprecate it earlier, but it simply didn't happen because the focus was usually on more enterprise oriented features/things rather than base syntax.

When Classes emerged it was considered dead, and maybe that decision (to replace the class stheir .NET and Objective C hosted adventures only confirmed that.

Later (2006-7) during the .NET adventures, implementing generics (first a .NET(2) only feature in D2007) probably triggered expansion of the record concept.  Because for generics specialized with records they needed operators and iterating (FOR...IN) to be bundled with the record, preferably as close to modern languages (.NET ,Java at the time) as possible, because Microsoft kept declaring till 2008-9 that native was dead.

Somehow the implementation of that, advanced records got delivered before (D2006)  the feature they were intended for, generics (D2007).

Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 11, 2021, 04:31:50 pm
@PascalDragon
Thanks, it is very useful. I will do some updates in my doc.

Still few things to further clarify:
I personally differentiate between instance and static fields/methods.

In the old days I also followed this naming, but then I got confused. In class, one can have class procedure PClass; and class procedure PClassStatic; static;. None of these two are "Instance methods", so as per your naming they are "Static methods", but only one of them is Static (no Self) the other is not. The common thing in these two, is the class keyword, hence I used the "class level method', to refer to them, but not plainly calling it "class method" to allow the naming work for object or record as well.
The other way would be to use instance/static for record and object, and instance/class for class.

If one only uses (I am still at object!) the PStatic method from above as you suggest, then one cannot use the tMyObject.P logic, what might be handy sometimes, e.g. if we do not want to make an instance at all (equivalent of making sure that regardless how many instances are declared they all behave as the same one, i.e. only class level fields and methods are declared).

So my - might be wrong - conclusion is that for object the best is to use class procedure PClass;, for class level methods. PClass has a benefit over PStatic as it can be called from the type, while PStatic cannot AND PClass also has a benefit over PClassStatic as it always has a Self, even if we do not want to use. Is it a wrong assumption?
Apparently I got confused even reading my own document (there in chapter 5.3 it was correct). So, just to put it straight:
In case of object, all class level methods can be defined three ways (procedure PStatic; static;, class procedure  PClass; and class procedure PClassStatic; static;).
The two static can be called as tMyObejct.Method, the one without static cannot.
The static without class is the traditional object structure and the other two has no benefit at all.
The static without class has a Self parameter unlike it is used in class, where static hasn't got a Self (there only class procedure X; static; can be static, without class, static alone is not even allowed).

I do not fully understand your reasoning, why the lack of meta object type should prevent using class procedure PClass; for object. But to me it is totally logic to say that the class keyword was invented later and it only works in object because object and class share some codebase in the compiler, but none of the two definitions starting with class, as above I corrected myself, have any advantages over the original procedure PStatic; static; definition.
Is it correct to say, or is it a stretch, that class keyword does not exist in object officially, so using class var FieldName and class procedure with or without static is only an abuse of the compiler's current behavior resulted from the shared codebase and it is not even guaranteed to work the same way?

@marcov
Thanks for the detailed explanation. I do not want to take a position whether object is dead or not. I saw people reasoning why a stack based structure is sometimes better than a heap pointer. One (like Delphi) can also say that for that you now have advanced record, but many feel that it is only an extra (even in mode objfpc need a modeswitch to use) and not a "core" solution.
My whole purpose of writing the doc was to clarify what is possible, what is not, and how to do that. So, we might say that object is dead, but as long as people use it, it is only half dead. I was (or at some smaller points still am) confused on the three animals (record, object, class), so I tried to collect all my questions in one place.
Now, based on PascalDragon's reply, I think I have peace in my mind regarding object, can clarify my doc and then object can live on in its own place.
Title: Re: OOP structures in fpc and Lazarus
Post by: marcov on November 11, 2021, 05:52:41 pm
@marcov
Thanks for the detailed explanation. I do not want to take a position whether object is dead or not. I saw people reasoning why a stack based structure is sometimes better than a heap pointer.

Any construct has its proponents. But it is a fact that objects haven't had any major new features since 1994.

I wanted to warn against taking such talk to seriously, since when advanced records were planned/added, TP objects probably never were on the table as a possible solution.

Quote
One (like Delphi) can also say that for that you now have advanced record, but many feel that it is only an extra (even in mode objfpc need a modeswitch to use) and not a "core" solution.

I'm no fan of mode objfpc, so I don't spend much attention to it. The reasons behind its design choices seem random to me. (as an older core member I do know some of original argumentations on a per feature basis, but I never saw much of a pattern in it)

Quote
My whole purpose of writing the doc was to clarify what is possible, what is not, and how to do that. So, we might say that object is dead, but as long as people use it, it is only half dead. I was (or at some smaller points still am) confused on the three animals (record, object, class), so I tried to collect all my questions in one place.

Note that TP Object is not deprecated in Free Pascal, mostly for the benefit of TP compatibility and the textmode IDE. Also Lazarus has/had some use of it (e.g. TLazIntfImage)

As far as why Delphi went with advanced methods, I tried to explain possible reasons why TP objects probably were not on the table. (long term legacy and backwards compatibility concerns, and a automatic VMT feature that had itscritics).

How you weave these things into your document, is your concern, but keep in mind that the opinion that they might as well have revived TP objects is not widely supported.
Title: Re: OOP structures in fpc and Lazarus
Post by: kupferstecher on November 11, 2021, 07:49:34 pm
Hello jollytall,

thanks for sharing! I just read it and have some remarks.

1. You chose the sequence record - advanced record - object - class
 For people learning OOP in my opinion this is not the best order. I'd choose the following order:
record - class - advanced record - object

When I leared OOP in FreePascal some years ago I found a tutorial in the internet that looked good and (although for Delphi) I worked it through. In the end it said object is deprecated, but class works nearly the same... For a beginner a bit frustrating.

2. About the memory locations, you distinguish between stack and heap. Although you mention the special situation of global variables, I think this is easily misunderstood. So I'd distinguish between three types of memory: the Static Memory for global variables, the Stack where local variables are saved and the Dynamic Memory (Heap) for runtime data.
Records and Objects save their fields directly in the static memory (globals) or Stack (locals), and can be saved in the Heap only with the use of pointers. The variables of classes in contrast only carry the address of the data fields that are allocated on the heap when calling the constructor.

3. You could mention what explicitely happens, when the constructor is called (Perhaps I just overread something).
MyClassInstance := tMyClass.Create;

tMyClass.Create calls the constructor of tMyClass. Therefore the compiler inserts some code to allocate the required memory for the class instance on the heap, initializes all variables, initializes the VMT if neccessary, calls the code of the 'constructor' and returns the memory address, which is then assigned to MyClassInstance.

4. About inheritance, you talk about the "closest" procedure that is called when useing virtual/override. I would add, that for overriding a procedure without virtual/override, the procedure to be called is determined on compile time and directly uses the type of the variable to determine which procedure to call. When using virtual/override, the procedure to be called is determined at runtime, according to the (derived) type that the instance actually has, 'independent' of the type that the variable has (but of course has to be of a derived type).

Regards
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 11, 2021, 09:54:28 pm
@kupferstecher

Thanks you for your comments. My comments, replies:

1. I was hesitating a bit on the sequence. Historically record, object, class, advanced record would have been the best. For current popularity and usability, probably class, record, advanced record, object would have been it. I chose the logic of complexity, features from the simplest to the most advances, i.e. record, advanced record, object, class. I don't think any is much better than the other. I think it is complex and due to different teams following different routes, there is no clear sequence of logic.
I agree that it is frustrating (not only for a beginner), this is why I tried to collect the questions I had.

2. Good point to highlight more when the memory allocation is done. I will try to rephrase it a bit. What you write is mainly correct and I tried to write the same in 3.5, also mentioning some other computer systems with different memory management tools, where I have very limited knowledge though.
What you do not mention, and if I go into these details I will have to add, although hidden somewhere among the lines it is there, that even for record and class types the class level (a.k.a. static) fields are reserved at compile time. What I do not know, but will have to investigate, what happens if a type is declared locally (nested type). Are the class level fields of them reserved in the static memory at start-up, or they only get allocated when the given code comes into scope, e.g. when a procedure is called? Also I will explain more that for classes the class constructors are called automatically (mentioned in 5.3 source code) and class level fields are reserved automatically. Here again I do not know, when exactly and where these fields are placed? Are they in the Heap like class instance fields or like global variables? If you know it, I would be glad if you could share, so I can include.
What my warning anyway, that due to the logic of Pascal, it should not really be a top priority for a programmer to go into the details of memory usage. Unless there is a special reason, I think the compiler takes care good enough.

3. Yes, I shall mention a bit more of it. I covered a bit this topic in 5.10 where I talked about fail, but I agree, it deserves a bit more (albeit it is well documented elsewhere, so I never had a question about it).
I also thought to mention more details about the virtual table, as that is an interesting topic in itself, how the "simple" VMT of object is structured vs. the more complex and better documented VMT of class.

4. I thought I covered that it great details, starting in 5.6 for object and even more, with all the ways to reintroduce and start a new virtual tree in class in 6.7. I might use a bit more the language of compile time and run time. What else do you miss there?

Thanks again,
Title: Re: OOP structures in fpc and Lazarus
Post by: VTwin on November 11, 2021, 09:58:48 pm
As has been pointed out, objects are basically deprecated. Some folks still use them, but if I was learning I would pass over them.
Title: Re: OOP structures in fpc and Lazarus
Post by: kupferstecher on November 11, 2021, 11:31:46 pm
Hello jollytall,

my suggestions were mostly on how to make it more clear to the reader, I think you already had the important topics covered. So it's more about how to describe the things.

To 1. I know rearranging is a lot of effort, so...
 
For current popularity and usability, probably class, record, advanced record, object would have been it.
I'd begin with record, as that is known by most programmers and a good basis to discuss classes. Also a programmer really needs to know/learn about records, but about object and advanced records I wouldn't say that. (Although in circumstances I use the object type myself).

To 2.
Quote
and I tried to write the same in 3.5, also mentioning some other computer systems with different memory management tools, where I have very limited knowledge though.
Yes, I recognized that. As said, I didn't consider anything wrong, its just a reader may focus too much on the stack. In the cases I personally use objects (not classes) they are never instantiated in local variables, so the whole stack thing doesn't apply there. Seems sometimes Stack is used in contrast to the Heap and actually means stack + static memory.
Quote
[...] that even for record and class types the class level (a.k.a. static) fields are reserved at compile time.
Never thought about that :)

Quote
what happens if a type is declared locally (nested type)
What do you mean by that? Classes can't be procedure-local, can they?

Quote
Also I will explain more that for classes the class constructors are called automatically (mentioned in 5.3 source code) and class level fields are reserved automatically. Here again I do not know, when exactly and where these fields are placed? Are they in the Heap like class instance fields or like global variables?
Perhaps that would be too detailed and of not much interest. As you said the compiler takes care of it. And I also don't know :) but believe they are allocated like global variables. I don't know if they are automatically zeroed like 'standard' fields.

To 4. Yes, your description is very detailed, my proposal was just to point out the compile-time/runtime difference to make the concept clearer.

--
Regards
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 12, 2021, 08:42:30 am
Quote
what happens if a type is declared locally (nested type)
What do you mean by that? Classes can't be procedure-local, can they?
Well, I did not know what happens as I had never tried that. Now I checked and so I know: You cannot do that, its a compile time error. One problem less. Thanks.

And I also don't know :) but believe they are allocated like global variables. I don't know if they are automatically zeroed like 'standard' fields.
It is difficult to test, since when the program starts it gets its memory that can easily be zero anyway. Anyway, I will make some test.
What I know though is, if you explicitly define a class constructor, that is called before the actual unit starts (as said later, units also run, if they have a begin end or initialization end section). I therefore assume that a default class constructor is called even if no one defined.
Title: Re: OOP structures in fpc and Lazarus
Post by: Thaddy on November 12, 2021, 09:23:32 am
I therefore assume that a default class constructor is called even if no one defined.
If you mean that a class definition with a class constructor, that is correct and documented.
It is not an assumption but a fact.
Note that the wiki errs at many points, but the manual explains this very well.
https://www.freepascal.org/docs-html/ref/refsu29.html

I.e: "The class constructor/destructor is called irrespective of the use of the class"

Again an example of Read The Friendly Manual...... (Oh, well:  >:D >:D >:D >:D >:D)
Forgot about that.... :P Could have done with two less devils... Did I use them this year?.. ::)
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 12, 2021, 09:52:35 am
No, it is not what I meant. I had read the manual, especially this part, before I wrote my doc. I wrote in my doc as well as in the last post, that if a class constructor is defined it is called automatically. It is clear from my tests and from this manual.
(I used the word, the class constructor is defined, not the word created, as used in the manual. This was to avoid confusion, though it might caused more. To me created means when we do create something and that is typically with a verb Create, what happens to be the constructor's name for class. Define is more that we write the code, so the class constructor exists.)

So the question was from kupferstecher, whether all class fields are zerod out when no class constructor is defined? When a class instance is instanciated (created) it can only be done through using the constructor, what is always available as derived from TObject, even if we do not redefine it. That in itself zeros out the instance fields.
But I did not find any documentation whether a class constructor is inherited from TObject and whether that is called automatically, or there is no guarantee that class fields are zero. The linked doc says that class constructor can be created (defined) to initialize class fields. But is it needed to zero them, or zero is already ensured?
It is difficult to test, as in a modern, large memory PC, the memory area used can easily be zero even without initialization.
Title: Re: OOP structures in fpc and Lazarus
Post by: Thaddy on November 12, 2021, 09:58:04 am
But is it needed to zero them, or zero is already ensured?
In principle the answer is yes. The exception is overriding NewInstance.
https://www.freepascal.org/docs-html/rtl/system/tobject.newinstance.html

BTW all this is documented as well.....(oh, well, go ahead... >:D 8-))

Explanation: NewInstance/ultimately InitInstance zeros out the memory for you.

Aside question: why do you not read the sources? They are free!
Title: Re: OOP structures in fpc and Lazarus
Post by: kupferstecher on November 12, 2021, 11:02:48 am
Thaddy, maybe there is still some misunderstanding?

This was about class vars. The docu of NewInstance only talks about instances.

Code: Pascal  [Select][+][-]
  1. Type TFoo = class
  2.   class var bar: Integer;
  3. end;

Is bar initialized to zero on program startup or not?

Title: Re: OOP structures in fpc and Lazarus
Post by: Thaddy on November 12, 2021, 12:29:47 pm
It is initialized to zero. There is no misunderstanding here.
It only CAN change behavior on overrides of NewInstance.

Anyway, the debugger will show you it is initialized.
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 14, 2021, 03:55:10 pm
Thanks for the many useful comments and answers. I made a new version and uploaded it to github (as again, it was suggested).

Few key changes:
Added a history and usability overview, clarifying the strong preference towards class and record vs. object and advanced record.
Specified more what to use in classes and objects even when the compiler allows both.
Corrected many smaller mistakes, typos, etc.

It is now uploaded as an editable document, but still it has to be downloaded. Maybe github is still not the best (or I did not find how to make it online visible), it would be better a web page to use.

The link:https://github.com/zsoltszakaly/OOPstructuresinpascal/blob/main/structures%20in%20pascal.odt (https://github.com/zsoltszakaly/OOPstructuresinpascal/blob/main/structures%20in%20pascal.odt)
Title: Re: OOP structures in fpc and Lazarus
Post by: marcov on November 14, 2021, 04:36:24 pm
Quote
TP objects are similar to records in many ways, but include basically everything that is needed for writing OO programs. It implemented methods, properties, inheritance, virtualization, constructors and destructors, i.e. practically everything that is needed for OOP.

Afaik TP didn't implement properties.

Quote
Later Embarcadero probably realized that the old object was not so bad after all,

IMHO that suggests a link that is simply not there.   The actual reasoning was copying from .NET to get similar generics, where structs carried operators as methods, so the specializing code could look in their definition for those operators, rather than scanning the global namespace for them. (where they might not even exist, e.g. if the record is type aliased)

Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 14, 2021, 09:19:25 pm
@marcov
Thanks for the clarifications.
Indeed TP had no properties as I also said it later in the document, but it remained incorrectly in the introduction. Will correct.
Also thanks for the reason on advanced record. Will also change that.
Title: Re: OOP structures in fpc and Lazarus
Post by: Blade on November 14, 2021, 09:48:50 pm
In regards to Turbo Pascal and Objects, I think it should be kept in mind that Turbo Pascal is freeware that is still used.  To include in some poorer countries, as a way to introduce Pascal.  This link at SourceForge is just one of many (https://sourceforge.net/projects/turbopascal-wdb/ (https://sourceforge.net/projects/turbopascal-wdb/)) where it can be downloaded.

I'm of the opinion that it is to the strategic advantage of Free Pascal/Lazarus to maintain portability and compatibility with Turbo Pascal (including with Objects), in order to be a viable alternative and "upgrade" path for those that happen to use or stumble across it.  Turbo Pascal was of such popularity at one time, that it still has significant recognition and public presence.

I would not disagree with anyone recommending Advanced Records or Classes over the use of Turbo Pascal style Objects, but I can see where it makes the transition easier for those that have a lot of Turbo Pascal code and projects, or have strongly established preferences for coding a certain way (like using Objects without Classes).
Title: Re: OOP structures in fpc and Lazarus
Post by: Blade on November 23, 2021, 07:55:13 pm
...various OOP structures, like advanced records, objects, classes...
P.S. It was written as.odt originally (55Kb), but it could not be attached, so I saved as .docx (47Kb).

Another place that might be great for your accumulated knowledge (and other advanced users), could be at Wikibooks for Pascal programming.  You can put in more information on OOP, in addition to link to your .odt/.pdf document.

https://en.wikibooks.org/wiki/Pascal_Programming (https://en.wikibooks.org/wiki/Pascal_Programming)
(Pascal Programming, Wikibooks)
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 24, 2021, 08:49:07 am
Thanks.
It is already on GitHub (see 6 posts above) as it had been suggested before. I don't mind anyone putting it on wikibooks, or probably the best would be if someone put a link there, so any possible further changes are not forked.
Title: Re: OOP structures in fpc and Lazarus
Post by: Thaddy on November 24, 2021, 02:33:58 pm
In regards to Turbo Pascal and Objects, I think it should be kept in mind that Turbo Pascal is freeware that is still used.  To include in some poorer countries, as a way to introduce Pascal.  This link at SourceForge is just one of many (https://sourceforge.net/projects/turbopascal-wdb/ (https://sourceforge.net/projects/turbopascal-wdb/)) where it can be downloaded.
No it is not. And the provided link is in violation of the original museum copyrights.
three versions of TurboPascal are still available from the museum at Embarcadero. (1.0, 3.0 and 5.5) but you should install Dosbox yourself and THEN install one of those versions to be legally compliant.
(btw: these versions work great on a Rasperry Pi with dosbox)
The re-packaging is not allowed. In that sense it is not freeware at all. It is free to use ware.And you need a registration/account to download it legally. Which is free... and the whole process is a doddle so I don't get it why that illegal distribution is on sourceforce. Only the museum will give you truly legal use of the software.

Again: you will need an EDN registration first, otherwise the - legal - links that can be found won't work, since you can not login.
Title: Re: OOP structures in fpc and Lazarus
Post by: Blade on November 24, 2021, 05:36:17 pm
No it is not. And the provided link is in violation of the original museum copyrights...
...three versions of TurboPascal are still available from the museum at Embarcadero. (1.0, 3.0 and 5.5) but you should install Dosbox yourself and THEN install one of those versions to be legally compliant.
...The re-packaging is not allowed. In that sense it is not freeware at all. It is free to use ware...

I'm not going to disagree with your point, as it might be technically correct.  However, it is merely a technicality in terms of usage or getting access to Turbo Pascal.  There are plenty of places that either allow download by 3rd parties other than Embarcadero, so the person doesn't have to sign up with them, or are providing downloads of packages that include both Dosbox and Turbo Pascal.  Even if the person doesn't want to use 3rd parties and makes sure they are in legal compliance, it's of a minor inconvenience to install Dosbox before downloading Turbo Pascal.  Usually such people would be highly enthusiastic and/or nostalgic types that are going to be sure to get it and play with it. 

If the SourceForge downloads per week are to be believed, it is a significant number of downloads, and that's just one of many sources.  It can be indicative of there still being interest in Turbo Pascal (Pascal in general), thus arguably, Free Pascal should position itself appropriately and as a "next step" to enthusiasts, hobbyist, independents, small businesses...

In regards to Objects/Records/Advanced Records versus Classes, there is also a kind of philosophical angle at work too.  Various people are going to prefer, feel more comfortable with, or choose the alternatives and not use Classes for their projects or particular program.  There is nothing wrong with that, especially if we are talking smaller programs and tasks, but even if they simply don't want to use such directly or minimize such usage.  People have/do/can make plenty of interesting and useful programs with Turbo Pascal style Objects. As long as they are useful and beneficial to them, hard to argue against their choices.  We also might want to keep in mind that there are some other popular languages that don't use Classes or can use Objects without Classes, such as Go, JavaScript, Lua, etc...  Free Pascal/Lazarus can be "philosophically" attractive to such users too, where they have more flexibility in the paradigm they want to use.

Part of what is great about Free Pascal/Lazarus is the features, options, and choices that it provides.
Title: Re: OOP structures in fpc and Lazarus
Post by: ArtLogi on November 30, 2021, 09:41:13 am
As has been pointed out, objects are basically deprecated. Some folks still use them, but if I was learning I would pass over them.
As a beginner comment. If 'Objects' are depricated, why is that most LCL more complex data structures (what ever they are called) begin with T and are inherited from TObject? How I can stop using those deprecated objects?  :o
Title: Re: OOP structures in fpc and Lazarus
Post by: MarkMLl on November 30, 2021, 10:19:00 am
As has been pointed out, objects are basically deprecated. Some folks still use them, but if I was learning I would pass over them.
As a beginner comment. If 'Objects' are depricated, why is that most LCL more complex data structures (what ever they are called) begin with T and are inherited from TObject? How I can stop using those deprecated objects?  :o

Have you read the document that this thread is discussing? Have you read the FPC etc. documentation?

Despite its name TObject isn't an object (in the sense of the "objects" introduced by Turbo Pascal and later documented).

It's the ultimate superclass of anything declared as a class, where a class can be instantiated into something which is commonly called "an object".

The terminology is unfortunate. Get used to it.

MarkMLl
Title: Re: OOP structures in fpc and Lazarus
Post by: howardpc on November 30, 2021, 10:29:16 am
As has been pointed out, objects are basically deprecated. Some folks still use them, but if I was learning I would pass over them.
As a beginner comment. If 'Objects' are depricated, why is that most LCL more complex data structures (what ever they are called) begin with T and are inherited from TObject? How I can stop using those deprecated objects?  :o
There is major confusion here, partly owing to the inherited and confusing use of the term "object" which can and does mean several things depending on context.

TP objects:
Code: Pascal  [Select][+][-]
  1. TTurboPascalObject = object...end;
are not deprecated in the FP compiler, only in the Delphi compiler.

Classes:
Code: Pascal  [Select][+][-]
  1. TpostTurboPascalClass = class(TObject)...end;
confusingly all descend from "TObject" but this is not a TurboPascal object, but a more complex and more capable construct. The naming was defined by Borland, not by FPC which uses it only to be compatible. However it is a source of confusion for newcomers.
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 30, 2021, 10:34:25 am
As a beginner comment. If 'Objects' are depricated, why is that most LCL more complex data structures (what ever they are called) begin with T and are inherited from TObject? How I can stop using those deprecated objects?  :o
Please check the document I wrote. This was actually one of the first pieces of confusion I had years ago, (followed by many others,) that caused me to start writing it.
Title: Re: OOP structures in fpc and Lazarus
Post by: ArtLogi on November 30, 2021, 12:58:56 pm
Thank you jollytall, I did read your article first public version, it was really nice read up for an amateur like me.

For the angry answer, yes I did actually verify the class vs. object in TObject declaration, but that would not have been any help to not to post beginners first thoughts.

PS. Isn't type SET also a primitive object datatype, kind of list-object as lack of better description.  :-\
Title: Re: OOP structures in fpc and Lazarus
Post by: PascalDragon on November 30, 2021, 01:20:36 pm
Classes:
Code: Pascal  [Select][+][-]
  1. TpostTurboPascalClass = class(TObject)...end;
confusingly all descend from "TObject" but this is not a TurboPascal object, but a more complex and more capable construct. The naming was defined by Borland, not by FPC which uses it only to be compatible. However it is a source of confusion for newcomers.

To add to the confusion: there exists a TObject (https://freepascal.org/docs-html/current/rtl/objects/tobject.html) that is a TP-style object in the Objects unit as that is the base type for Turbo-/FreeVision. :-\
Title: Re: OOP structures in fpc and Lazarus
Post by: MarkMLl on November 30, 2021, 01:29:26 pm
PS. Isn't type SET also a primitive object datatype, kind of list-object as lack of better description.  :-\

Set is one of the fundamental types which Wirth put into the language at its inception, and (simplifying somewhat) comprises the individual bits in a register or memory location. It shouldn't be considered as a list, since it is by definition unordered.

My simplification was that the limit on a set is generally implementation-defined but somewhat larger than the number of bits in a word. 256 was typical until comparatively recently, i.e. enough to represent the ASCII character set.

MarkMLl
Title: Re: OOP structures in fpc and Lazarus
Post by: Warfley on November 30, 2021, 02:40:19 pm
PS. Isn't type SET also a primitive object datatype, kind of list-object as lack of better description.  :-\
Yes. Sets in pascal are, unlike in other languages like Python, Swift or C++, not general sets, but Bitset, i.e. their size is known at compile time and their access is always in constant time (with bit operations). Originally they where introduced into pascal to have a more highlevel concept representing the bit-flags typically used by C programs.
For example, where a C program would get an integer where you OR your flags together as an argument, Pascal provides a set, where you can do set operations (like union and inclusivity checks) on. Technically the same things happen, you can also cast sets into bit words (like integers), it's just a more high level construct. Originally pascal also did not have bit operations, as it was intended that everything should be done with sets
But due to the compatability with bit words, they are restricted only to datatypes directly representable as Integers (theoretically every data can be represented as an integer but thats not considered)
Title: Re: OOP structures in fpc and Lazarus
Post by: marcov on November 30, 2021, 04:13:14 pm
Technically the same things happen, you can also cast sets into bit words (like integers), it's just a more high level construct.

Note that it is not, as it is a kind of like a higher level intrinsic. If the CPU supports bit level addressing or explicit bit set instructions, it can use these instead of and and orring.

Of course some of the more advanced compilers have ways of detecting a clean AND or OR to a value, and convert it. But the fact that many embedded C compilers (Keil, Microchip) have extensions for bit level access seems to indicate it is not that simple.
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on November 30, 2021, 06:09:38 pm
For the angry answer
I don't know if you mean me had an angry answer, but if that is what you feel, you feel it wrong. There was nothing angry in it, (hence the 'Please' and the mentioning that I had the same confusion).

PS. Isn't type SET also a primitive object datatype, kind of list-object as lack of better description.  :-\
Sets are covered by the experts in the last few posts in details, so I cannot add much to it. I however mentioned it in Chapter 2.2 as a structure (like e.g. arrays as well) that I do not deal with, as for OOP they have no relevance.
Title: Re: OOP structures in fpc and Lazarus
Post by: ArtLogi on December 01, 2021, 12:25:05 pm
For the angry answer
I don't know if you mean me had an angry answer, but if that is what you feel, you feel it wrong. There was nothing angry in it, (hence the 'Please' and the mentioning that I had the same confusion).
Sorry for lack of clarity in my post.

No I meant _other_ responders who were irked by this statement of TObject.  :)
PS. Isn't type SET also a primitive object datatype, kind of list-object as lack of better description.  :-\
Sets are covered by the experts in the last few posts in details, so I cannot add much to it. I however mentioned it in Chapter 2.2 as a structure (like e.g. arrays as well) that I do not deal with, as for OOP they have no relevance.
Yes, answers were nice. I also need to re-read your really nice summary article again.


edit. For clarity I move this following "braindump" at the end here:

Quote
(even though, I do not see much difference - as of defining by type and using such [in build] handlers to access them - compared records, looking from again from surface. As in the end any structure is just series of preset and latching bits in oscillator screen if we dive deep enough). I do not want to derail this topic by trying to figure out what SET is or is not.

I will do end discussion of SET and a lists from my part to this quote from Merriam-Webster dictionary, as non-native English user: "List: a simple series of words or numerals (such as the names of persons or objects)"
Title: Re: OOP structures in fpc and Lazarus
Post by: MarkMLl on December 01, 2021, 01:21:04 pm
No I meant _other_ responders who were irked by this statement of TObject.  :)

I'm sorry, that was probably me.

I agree, the choice of names is irksome :-)

Quote
I will do end discussion of SET and a lists from my part to this quote from Merriam-Webster dictionary, as non-native English user: "List: a simple series of words or numerals (such as the names of persons or objects)"

Yes, but note that while there is no explicit statement as to whether or not that's ordered the word "series" implies it is.

The important point is that sets are unordered, and set elements are uncounted. So adding an element to a list twice has exactly the same result as adding it once, and once you've removed an element removing it a second time has no effect.

(That reads like the start of Laws of Form, which might be familiar to some.)

MarkMLl
Title: Re: OOP structures in fpc and Lazarus
Post by: Warfley on December 01, 2021, 02:47:02 pm
I will do end discussion of SET and a lists from my part to this quote from Merriam-Webster dictionary, as non-native English user: "List: a simple series of words or numerals (such as the names of persons or objects)"

Well that is the common understanding of a list, but we are talking about programming here, and as such have our own terminology (the same way that the dictionary definition of a tree says something about wood, while for computer scientists a tree is a datastructure).
There are professional glossaries, for example wikipedia has a neat one for CS terminology: https://www.wikiwand.com/en/Glossary_of_computer_science
List:
Quote
An abstract data type that represents a countable number of ordered values, where the same value may occur more than once. An instance of a list is a computer representation of the mathematical concept of a finite sequence; the (potentially) infinite analog of a list is a stream.[139]: §3.5  Lists are a basic example of containers, as they contain other values. If the same value occurs multiple times, each occurrence is considered a distinct item.
Set:
Quote
Is an abstract data type that can store unique values, without any particular order. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests a value for membership in a set.

Language is not really universal, each profession has it's own terminology and means potentially completely different things. A big part of learning a profession is learning the terminology to efficiently communicate
Title: Re: OOP structures in fpc and Lazarus
Post by: Blade on December 01, 2021, 05:35:08 pm
advanced records...
...provide feedback.
...any comment you have or any topic that should be added...

"In the world of Free Pascal, one can question what to use advanced records at all, when object is still
fully supported and class is also available. Probably it is again not a top priority to use...
...Advanced records, or also called extended records are a rarely used feature of Pascal."

Outside of correcting the grammar, the document seems to give some mixed signals about advanced records.  I don't think that was necessarily the intention, as it's conveyed that OOP is a tool to use when appropriate. Maybe the introduction language used about advanced records should be neutral, where they are presented as being of equal standing to OOP's objects and classes.  Kind of like, "another tool in the toolbox".

Later in the document, how advance records compare to other structures are given, which is good information.  I'm just emphasizing the introduction, as a newbie/beginner might get a negative impression, as it's something not needed.  However, many users of Free Pascal can be hobbyists, IT personnel, workers or owners of a small business creating utility programs for productivity, etc...  In the context of the task or smaller size of the programs they are creating, records or advanced records could be highly suitable.
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on December 01, 2021, 07:22:41 pm
Well, if it gives mixed signals, it might be because I have mixed feelings. My approach is the following:
- Advanced records are really a rarely used feature in the Free Pascal world. I do not have statistics, but it would be interesting to see how many one can find vs. e.g. class.
- Experts clearly stated above in the discussion, that it is there in FPC for full Delphi compatibility and also the reason is given why Embarcadero created it at the first place.
- If there is a tool and that is the best for a given purpose, we should not be shy to use it. This is why I detailed it.
- However there are not too many real usecases where advanced records have a real benefit. To me the only one is the variable record with methods, although I have never come across such a case in real life.
- As it is clear from my document, all these structures behave slightly differently in different cases, and for the hobbyists and alike, that would be an extra reason not to use advanced records. Somebody who is not using these features every day, it is much easier to remember only one-two structures. My recommendation after studying them for some time, if somebody starts programming and does not have a very strong argument to use something else, stick to only two structures, record for very simple cases and class for everything else where OO features are needed.

Last my trump card: I like if my programs are clean and simple and are based on the standard of the tool I use. So, I try to stick to mode objfpc and advanced records are simply not there (except if its modeswitch is used).

Nonetheless, if you have a suggestion how to change some of the sentences, I am happy to modify.
Title: Re: OOP structures in fpc and Lazarus
Post by: winni on December 01, 2021, 07:45:35 pm
Hi!

Have a look in unit Types:

The very  basic structures meanwhile are advanced record:

TSize, Rect, RectF, Point, PointF ....

Winni
Title: Re: OOP structures in fpc and Lazarus
Post by: Blade on December 02, 2021, 12:54:25 am
Nonetheless, if you have a suggestion how to change some of the sentences, I am happy to modify.

I think there are 3 elements to this:

1) Opinion and sentiment

This is kind of tricky, thus I gave you a bit of gentle push back.  I don't think it's my place to directly interfere or edit what an author wants to convey to the audience.  It is arguably better to ask you to elaborate about a point, to have a greater understanding about your views, and then for you decide how you want the information presented.  Your experience with using Object Pascal is totally valid.  It's great that we can discuss our different views, and maybe find common ground or learn something new.

2) Factual data

You are doing a good job on this.  Clearly, you have done your homework.  Where you are unsure about something, you are asking questions.  I think it's best for the more advanced users and developers (as is happening) to make those corrections as they see fit to.

3) Grammar and spelling

I can be of some help on this aspect.  Once there is a more mature version of the document, then people such as myself can make corrections for greater clarity.  In order to get a finished document, it's not anything to worry too much about for now, and it's arguably better not to interfere with a person's writing process.

Quote
I like if my programs are clean and simple...


Totally agree.  I always try to go the simple route first, before adding complexity.  But, we must admit that there are many views and directions that a programmer can have or choose.  This is why I like Object Pascal, because we have great options that can be used as necessary.
Title: Re: OOP structures in fpc and Lazarus
Post by: PascalDragon on December 02, 2021, 09:15:57 am
- However there are not too many real usecases where advanced records have a real benefit. To me the only one is the variable record with methods, although I have never come across such a case in real life.

Advanced records compared to classes or objects can have operator overloads that are part of the record itself. This allows the operators to be used inside generics which otherwise need to know the operators while the generic itself is declared.

For example:

Code: Pascal  [Select][+][-]
  1. program tgentest;
  2.  
  3. {$mode objfpc}
  4. {$modeswitch advancedrecords}
  5.  
  6. uses
  7.   fgl;
  8.  
  9. type
  10.   TTest1 = record
  11.     a: LongInt;
  12.   end;
  13.  
  14.   TTest2 = record
  15.     a: LongInt;
  16.     class operator = (const aLeft, aRight: TTest2): Boolean;
  17.   end;
  18.  
  19. class operator TTest2.=(const aLeft, aRight: TTest2): Boolean;
  20. begin
  21.   Result := aLeft.a = aRight.a;
  22. end;
  23.  
  24. operator = (const aLeft, aRight: TTest1): Boolean;
  25. begin
  26.   Result := aLeft.a = aRight.a;
  27. end;
  28.  
  29. type
  30.   // this will complain about the missing = operator
  31.   //TTest1List = specialize TFPGList<TTest1>;
  32.   // this works however
  33.   TTest2List = specialize TFPGList<TTest2>;
  34.  
  35. var
  36.   t1_1, t1_2: TTest1;
  37.   t2_1, t2_2: TTest2;
  38. begin
  39.   t1_1.a := 42;
  40.   t1_2.a := 21;
  41.   t2_1.a := 2;
  42.   t2_1.a := 4;
  43.   // the comparisons will work for both types
  44.   if t1_1 = t1_2 then
  45.     Writeln('Foo');
  46.   if t2_1 = t2_1 then
  47.     Writeln('Bar');
  48. end.
  49.  

Also Delphi code is very likely to use advanced records, because TP-style objects are considered deprecated there.
Title: Re: OOP structures in fpc and Lazarus
Post by: MarkMLl on December 02, 2021, 09:41:59 am
Advanced records compared to classes or objects can have operator overloads that are part of the record itself. This allows the operators to be used inside generics which otherwise need to know the operators while the generic itself is declared.

Nice one :-)

MarkMLl
Title: Re: OOP structures in fpc and Lazarus
Post by: howardpc on December 02, 2021, 10:14:03 am
A further advantage of advanced records in some situations is their built-in support for methods associated with variant (union-style) record parts. Classes do not allow direct declaration of any variant part.


Of course you can have a variant record field in a class instance if need be, but this is then a bolt-on and not as lightweight as directly declared in an advanced record, and it also requires an additional name layer in order to access the variant's fields, complicating the syntax.
Variant records have their limitations (you can't include fields of any managed types), but also allow an old-school versatility that is an advantage in some scenarios.
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on December 09, 2021, 12:46:52 pm
Thank you all for the comments.
I tried to rewrite the introduction and the advanced record parts to reflect more the above discussion, also linking information from herein.
I also added a new subchapter on the fail in inherited structures, as discussed here: https://forum.lazarus.freepascal.org/index.php/topic,57379.0.html (https://forum.lazarus.freepascal.org/index.php/topic,57379.0.html)
Title: Re: OOP structures in fpc and Lazarus
Post by: ArtLogi on February 10, 2022, 12:11:21 am
Any interest to say a few words about exceptions as they are objects, but are kind of threaded as separate case entirely in most of the time.. Really confusing to those who don't have found the key Exception are specialiced objects".. The clause "all objects are inherited from TObject and therefore start with T", but wait there is exception...   %)
Title: Re: OOP structures in fpc and Lazarus
Post by: jollytall on February 10, 2022, 08:42:47 am
Interesting question. It indeed might worth few words in the next revision.
However, although Exception looks as something special it is not really. What is really special is the raise and the two structures to do something with the raised exception: try..finally..end and try..except..end.
If you look at the following code, it is perfectly valid:
Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. {$mode objfpc}
  4.  
  5. uses
  6.   SysUtils;
  7.  
  8. var
  9.   i : integer;
  10.  
  11. begin
  12. readln(i);
  13. try
  14.   if i = 2 then
  15.     raise TObject.Create();
  16. except
  17.   writeln('In except');
  18.   end;
  19. end.

The object (class instance) raised by raise does not need to be of class type Exception.
If you remove the try..except..end from the above program, it still prints an exception (if i = 2) on screen from SysUtils, like
Code: [Select]
An unhandled exception occurred at $00000000004010DA:
Exception object TObject is not of class Exception.
  $00000000004010DA  main,  line 12 of project1.lpr
If you even remove SysUtils, then you get a Runtime error, like
Code: [Select]
Runtime error 217 at $0000000000413FA2
  $0000000000413FA2
  $0000000000422D5C
i.e. SysUtils prints the message from the Exception if that is used to call raise, or prints the type of the class instance if it is not an Exception (or its descendant). You can try to raise an exception with other TObject descendants (I tried TStringList and it works the same).
If there is no SysUtils then a simple error message is generated as noone catches the raised exception.

The clause "all objects are inherited from TObject and therefore start with T", but wait there is exception...   %)
I might not know my doc well enough, but I do not remember this quote (and cannot find it in it, neither in the Wiki under Class). Is it from somewhere else? Btw. you can name your class type (almost) anything you want to, so those who wrote SysUtils were perfectly allowed to call their class type: Exception. To my taste TException would fit better, but "De gustibus non est disputandum".
Title: Re: OOP structures in fpc and Lazarus
Post by: PascalDragon on February 10, 2022, 08:54:49 am
The clause "all objects are inherited from TObject and therefore start with T", but wait there is exception...   %)

As jollytall wrote the first part is true for exceptions as well. The base type Exception inherits from TObject as well.

And regarding the name: those are up to the user anyway. The compiler isn't enforcing anything there. It's just that T is the usual prefix for types with a special exception (pun not intended) for exception types which start with E. This allows for a better distinction as the later are normally only used in the context of exception handling.
Title: Re: OOP structures in fpc and Lazarus
Post by: Warfley on February 10, 2022, 03:00:52 pm
Really confusing to those who don't have found the key Exception are specialiced objects".. The clause "all objects are inherited from TObject and therefore start with T", but wait there is exception...   %)
Inheriting from TObject is not the reason they start with T, because otherwise, why doe TPoint or TRect, which are records start with T.

AFAIK the convention is so that custom types should in their name indicate what they are. Exceptions start with E (e.g. EConvertError), Interfaces with I (e.g. IUnkown) and Pointer with P (PInteger). All other types start with a generic T for Type (e.g. TPoint).

This is very usefull, if you have multiple related types like a TPoint is the record, PPoint is a pointer to the record, or a class TTest which implements interface ITest.
Even more so, as every type starts with such a prefix, functions and variables can have the name too, like the function Point that creates a TPoint. And following this convention can be really helpful to create a kind of constructor function with the same name of a type without the Prefix.

Also note that exceptions all inherit from Exception class is just a convention from the SysUtils unit, you can use exceptions with arbitrary objects as data (maybe even arbitrary pointers?)
Title: Re: OOP structures in fpc and Lazarus
Post by: PascalDragon on February 11, 2022, 12:47:07 pm
Also note that exceptions all inherit from Exception class is just a convention from the SysUtils unit, you can use exceptions with arbitrary objects as data (maybe even arbitrary pointers?)

No, raise and the on-clause expect a TObject or a descendant thereof.
TinyPortal © 2005-2018