What is the difference between the new ADVANCED RECORD and the old OBJECT?
And after almost 3 years, are there real difference to justify advanced records or it is just to follow Delphi?
And after almost 3 years, are there real difference to justify advanced records or it is just to follow Delphi?
IMHO people glorify the old object for no good reason.
IMHO people glorify the old object for no good reason.
No good reason until -IMHO people glorify the old object for no good reason.
I have no feelings about that. I want to move on, using what programmers might use nowadays, but I'm not sure if the object type is deprecated of not. IIRC, Delphi says yes, it's deprecated. However, as have already pointed here,
p.s. I don't buy the performance argument at all, since that can be done with advanced records as well. Even before advanced records I used records for that with procedures operating on them. I don't see the reason to have yet another structured type for that.If you read carefully I made the point it used to be the case.... Advanced records changed that a bit.
Do advanced records support inheritance? AFAIK no.
One often has different records with a common header.
Here base objects which will be inherited by specialized objects are convenient. For many cases classes (TObject descendants) have too much not needed overhead so "old style" objects fit well.
In MSElang "object" and "class" are almost the same. "class" instances are always allocated on heap and provide implicit pointer dereference. "object" is instantiated as stack- or global-variable or on heap if the "object" has a constructor and a destructor, see
https://gitlab.com/mseide-msegui/mselang/wikis/home/mselang_objects
MSElang objects and classes can have variant parts, classes can inherit from objects.
Did you ever made a compiler for example? OK, a compiler is maybe a cornercase but it's lists are full of header-paydata structures, often even multi level.QuoteOne often has different records with a common header.
Here base objects which will be inherited by specialized objects are convenient. For many cases classes (TObject descendants) have too much not needed overhead so "old style" objects fit well.
Yeah, or just read the general header and a separate header for the extensions. These (doutbful!) cornercases are not really motivations IMHO to keep a complete object model running.
In MSElang the [virtual] object/class header attachment defines it. There is no VMT without [virtual].In MSElang "object" and "class" are almost the same. "class" instances are always allocated on heap and provide implicit pointer dereference. "object" is instantiated as stack- or global-variable or on heap if the "object" has a constructor and a destructor, see
https://gitlab.com/mseide-msegui/mselang/wikis/home/mselang_objects
MSElang objects and classes can have variant parts, classes can inherit from objects.
If I would start over, that's probably what I would do, with one exception. I would leave objects pure structures, so no VMT (and thus probably no virtual).
One of the things I hate most about TP objects, is that you can't immediately see if it is a pure record or an object.
Did you ever made a compiler for example? OK, a compiler is maybe a cornercase but it's lists are full of header-paydata structures, often even multi level.
In MSElang the [virtual] object/class header attachment defines it. There is no VMT without [virtual].
(and the second annoyance about TP object btw is the manual pointer declaration for objects.I don't understand. What do you mean with "manual pointer declaration for objects"?
If we ever align advanced records to class in the same way, something like that could solve that yes. Though I would lean towards simply forbidding vmt beyond class level.Why not universal and orthogonal? Also classes without VMT have it's use, MSElang supports it.
To mention another important difference between object and record that also was (aside from Delphi compatibility) the main reason to add methods to records in the first place: advanced records can contain operator overloads as part of themIn MSElang operator overloading is also done in objects/classes with the [operator=] method attachment.
Feature | Record | Object | Class |
Encapsulation (combining data and methods + hiding visibility) | Yes | Yes | Yes |
Inheritance | No | Yes | Yes |
Class constrcutor and destrutor | Yes | Yes | Yes |
Polymorphism (virtual methods) | No | Yes | Yes |
Memory allocation | Stack | Stack | Heap |
Operator overload (global) | Yes | Yes | Yes |
Operator overload (in type only) | Yes | No | No |
Type helpers | Yes | No | Yes |
Virtual constructors, class reference | No | No | Yes |
If we compare records and objects and classes in in FPC now, thenThis nice comparison table should end up in a wiki...
I concur with the above. Very nicely done Serge.If we compare records and objects and classes in in FPC now, thenThis nice comparison table should end up in a wiki...
Don't forget management operators for records. (3.2+)Thanks for the update, Thaddy
Also note that advanced records do have a VMT if these are used.
So, nowadays, why should I choose advanced records instead of object type?
@ASergeBut unlike for objects that is not part of the record "instance", but only part of the Init RTTI metadata, thus per type.
Don't forget management operators for records. (3.2+)
Also note that advanced records do have a VMT if these are used.
Thanks for adding the difference...@ASergeBut unlike for objects that is not part of the record "instance", but only part of the Init RTTI metadata, thus per type.
Don't forget management operators for records. (3.2+)
Also note that advanced records do have a VMT if these are used.
Feature | Record | Object | Class |
Encapsulation (combining data and methods + hiding visibility) | Yes | Yes | Yes |
Inheritance | No | Yes | Yes |
Class constrcutor and destrutor | Yes | Yes | Yes |
Polymorphism (virtual methods) | No | Yes | Yes |
Memory allocation | Stack | Stack | Heap |
Operator overload (global) | Yes | Yes | Yes |
Operator overload (in type only) | Yes | No | No |
Type helpers | Yes | No | Yes |
Virtual constructors, class reference | No | No | Yes |
Variant part (case) as c++ union | Yes | No | No |
Bitpacked (really packing) | Yes | No | No |
objects can be bitpacked....Carefully read "really packing". In you example bitpacked the same as packed. Packed supported by objects.
Carefully read "really packing". In you example bitpacked the same as packed. Packed supported by objects.I can't find any documentation for that, but a test showed you right.
Which makes you wonder if that is not a bug (either bitpack objects or do not accept the syntax)FWIW, it should probably be considered a bug since the Free Pascal Reference Guide, Chapter 5, section 5.1 does _not_ list "bitpacked" as an option when declaring objects, only "packed" is shown as being syntactically acceptable.
and there really aren't any docs about it (including trunk docs)There are no docs about it... other than the Free Pascal Reference Guide (of course... for you, that's not documentation.)
If I refer to documentation it is always the true documentation, but there is no reference to bitpacked objects in the reference guide.and there really aren't any docs about it (including trunk docs)There are no docs about it... other than the Free Pascal Reference Guide (of course... for you, that's not documentation.)
If I refer to documentation it is always the true documentation, but there is no reference to bitpacked objects in the reference guide.FreePascal Reference Guide - 3.3 Structured Types (https://www.freepascal.org/docs-html/ref/refse14.html#refsu14.html)
However, Free Pascal allows controlling the layout with the Packed and Bitpacked keywords. The meaning of these words depends on the context:
...
When using the bit packing mechanism, the compiler calculates for each ordinal type how many bits are needed to store it. The next ordinal type is then stored on the next free bit. Non-ordinal types - which include but are not limited to - sets, floats, strings, (bitpacked) records, (bitpacked) arrays, pointers, classes, objects, and procedural variables, are stored on the first available byte boundary.
First there were record, procedures and functions.
Next, with the emergence of OOP, there were objects.
Next, Borland has introduced classes in which there are additional opportunities. And to force everyone to switch to a new way of declaration, a objects was sign as deprecated.
Later, when it was necessary to merge fields and methods again, it was already inconvenient to revive objects declared as deprecated. And decided to expand records.
And, accordingly, all the new features have tried to do only for records, skipping the implementation for objects, so that they correspond to the previously established policy. And either intentionally made mistakes in the support of old objects, or rather greatly inflated random errors to convince not to use objects.
Feature Record Object Class
Class constrcutor and destrutor Yes Yes Yes
The very first line of ASM code Is missing with the 3.2.0.
First there were record, procedures and functions.
Next, with the emergence of OOP, there were objects.
Next, Borland has introduced classes in which there are additional opportunities. And to force everyone to switch to a new way of declaration, a objects was sign as deprecated.
Later, when it was necessary to merge fields and methods again, it was already inconvenient to revive objects declared as deprecated. And decided to expand records.
And, accordingly, all the new features have tried to do only for records, skipping the implementation for objects, so that they correspond to the previously established policy. And either intentionally made mistakes in the support of old objects, or rather greatly inflated random errors to convince not to use objects.
The classes concept already existed in the Clascal (https://wiki.freepascal.org/Clascal) language for Apple's Lisa computer (the earliest object-oriented Pascal dialect), but it was abandoned by Larry Tesler after being advised by Niklaus Wirth. Later, classes were reintroduced by Borland for Delphi.
In many cases and other languages, people often just want extensible associative arrays and the convenience of dot notation, not the baggage of Class-based OOP.
Be that as it may, clearly there is a place for the "plain" object concept or a simpler implementation of OO that is not so class-centric.
Be that as it may, clearly there is a place for the "plain" object concept or a simpler implementation of OO that is not so class-centric.
The trouble is that for that small class of cases you either have to have a lot of explicit reference usage around it (like in C++ but I assume that could also be done smarter) or have two OO models.
Neither is a very attractive solution. Moreover we already have 5MLoc of class based code.
QuoteFeature Record Object Class
Class constrcutor and destrutor Yes Yes Yes
The constructor for record is not really constructor. Memory is allocated by the definition of a record variable, and its constructor does only the initializing functions.
Destructors are not allowed for record.
- if we use a recNew:= TRecord.Create(...);, does recNew point towards an allocated memory inside the stack (I'm worried about stackoverflow), or inside the heap like objects?
- as there are no destructors for such advanced records, are they deallocated automatically? Whether they are in the stack or in the heap?
>
> Does anyone know if TFPGList will work with records (I know it works
> with simple datatypes like integer and string)?
>
You will have to use Pointer to record and allocate them yourself, it seems, with p:=New(TAdvRecord) or something.
During my experiments I ran into that. Should be solvable.
Btw, @Serge writes constructor Init and not constructor Create in the records. I think it's probably to disconfuse between "constructors", whether it is an object instance (Create, i.e. located in the heap) or an advanced record variable (Init, i.e. located in the stack).
So, as far as I understand, nothing magic in memory allocation, including with this advanced records and their "constructor Init" (that said, it - the compiler - still does a lot of work for us in the background to automatically manage a specialized "type safe" container-list-map-..., even with these advanced records).