Any idea, what can be wrong?I'm sorry. but your approach to distributing the techy information in 21st century is wrong.
I'm sorry. but your approach to distributing the techy information in 21st century is wrong.
Lazarus also uses fpc as the compiler, so it is not necessary to mention Lazarus when discussing language features (IMHO).
"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?
It is a shame, the zip-ed pdf is still 220 Kb.
If it ain't broke, don't fix it.
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.Lazarus also uses fpc as the compiler, so it is not necessary to mention Lazarus when discussing language features (IMHO).
"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 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.
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.
- 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.
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.
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.
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).
procedure PNothing; procedure PStatic; static; class procedure PClass; 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?
I personally differentiate between instance and static fields/methods.
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).Apparently I got confused even reading my own document (there in chapter 5.3 it was correct). So, just to put it straight:
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?
@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.
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).
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.
[...] that even for record and class types the class level (a.k.a. static) fields are reserved at compile time.Never thought about that :)
what happens if a type is declared locally (nested type)What do you mean by that? Classes can't be procedure-local, can they?
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.
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.Quotewhat happens if a type is declared locally (nested type)What do you mean by that? Classes can't be procedure-local, can they?
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.
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.
But is it needed to zero them, or zero is already ensured?In principle the answer is yes. The exception is overriding NewInstance.
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.
Later Embarcadero probably realized that the old object was not so bad after all,
...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).
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.
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...
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
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.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
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? :oPlease 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.
Classes: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.
TpostTurboPascalClass = class(TObject)...end;
PS. Isn't type SET also a primitive object datatype, kind of list-object as lack of better description. :-\
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.
Technically the same things happen, you can also cast sets into bit words (like integers), it's just a more high level construct.
For the angry answerI 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.
Sorry for lack of clarity in my post.For the angry answerI 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).
Yes, answers were nice. I also need to re-read your really nice summary article again.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.
(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)"
No I meant _other_ responders who were irked by this statement of TObject. :)
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)"
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)"
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:
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.
advanced records...
...provide feedback.
...any comment you have or any topic that should be added...
Nonetheless, if you have a suggestion how to change some of the sentences, I am happy to modify.
I like if my programs are clean and simple...
- 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.
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, likeRuntime 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).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".
The clause "all objects are inherited from TObject and therefore start with T", but wait there is exception... %)
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.
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?)