Lazarus

Free Pascal => Beginners => Topic started by: malcome on December 10, 2015, 09:17:34 am

Title: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: malcome on December 10, 2015, 09:17:34 am
What is the difference between the new ADVANCED RECORD and the old OBJECT?

Code: Pascal  [Select][+][-]
  1.  
  2. {$mode objfpc}{$H+}
  3. {$modeswitch ADVANCEDRECORDS}
  4.  
  5. type
  6.   TOld = object
  7.   private
  8.     function getheight: integer;
  9.     procedure setheight(AValue: integer);
  10.   public
  11.     property Height: integer read getheight write setheight;
  12.   end;
  13.  
  14.   TNew = record
  15.   private
  16.     function getheight: integer;
  17.     procedure setheight(AValue: integer);
  18.   public
  19.     property Height: integer read getheight write setheight;
  20.   end;
  21.  
  22. var
  23.   Fnew: TNew;
  24.   Fold: TOld;
  25.  
  26. begin
  27.   Fnew.Height := 100;
  28.   Fold.Height := 200;
  29.   writeln(Fnew.Height);
  30.   writeln(Fold.Height);
  31. end.
  32.  
  33.  

Thank you.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: balazsszekely on December 10, 2015, 09:32:10 am
@malcome

Try to inherit something from TOld then from TNew and you'll see the difference. ;)
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: malcome on December 10, 2015, 10:00:39 am
Hi GetMem.
Only that? :o IMHO,it is atrophy.:D
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: marcov on December 10, 2015, 10:54:34 am
Make a method virtual in the object case, and compare the sizeofs()
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Graeme on December 10, 2015, 12:32:03 pm
What is the difference between the new ADVANCED RECORD and the old OBJECT?

Delphi broke OBJECT support and reinvented the wheel a couple years later with "advanced records".  In FPC  you require an extra compiler mode to enable advanced records.

FPC has never broken OBJECT's, and they are the precursor to CLASS. I like them and use them often. I may be old school (from my TP days), but for me a RECORD is a structure without methods, so that's why I don't use Advanced Records in any of my code.

In the end I guess they do the same thing though.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: mdbs99 on September 29, 2018, 05:19:27 pm
And after almost 3 years, are there real difference to justify advanced records or it is just to follow Delphi?

Thanks.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: marcov on September 29, 2018, 05:36:48 pm
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.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Awkward on September 29, 2018, 05:44:04 pm
I using old objects in some places. Not because they have New/Dispose extensions but for object inheritances
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: lucamar on September 29, 2018, 06:09:13 pm
And after almost 3 years, are there real difference to justify advanced records or it is just to follow Delphi?

Following Delphi has its merits, if not done blindly; after all, Delphi is the "leader" in Pascal programming and lots (most?) of new Pascal code is written using their extensions.

With respect to advanced records, old-style objects and classes ... well, they can be seen as gradations of a concept: in the lower level advanced records, a little beyond that old-style objects and last the more powerful classes. And while it is true that adv. records and old-style objects differ only a little---basically, beyond implementation details, in inheritance capability---they still differ enough that an election has to be made between using one or the other type ... or jump directly to a class.

IMHO people glorify the old object for no good reason.

I don't think "glorify" is the adequate word here. There are times---not many, granted---when one needs something more than records but a class is, somehow, overkill. In that middle ground is where the object type fits.

That is, unless records keep "advancing" and become objects  :)
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: mdbs99 on September 29, 2018, 06:28:58 pm
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, object type is different to advanced records...

So, nowadays, why should I choose advanced records instead of object type?
(the answer should not only consider that Delphi deprecated object but, instead, explain the technical reasons)

regards,
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Thaddy on September 29, 2018, 06:48:53 pm
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,
No good reason until -
- advanced records showed up.
- there is still stack vs heap.
Nowadays I don't take notice of it unless I absolutely need performance (read below: these days are gone) and objects are still the better option there.
Funny thing is that features of advanced records are bolted on old school objects... something I don't think is a particularly wise decision...

Hey, if you want managed types use C#? (Utter respect in most language decisions but some are rubbish).
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: marcov on September 30, 2018, 12:50:32 pm
Well, inheritance is a point. In theory you could also have static base "objects" deep in your framework, and later derive real objects (as in capable of polymorphism) deeper.

On the flip side however, for those mostly shallow advantages, you would be stuck with a 1990 era object model, manually declaring pointers to objects forever etc etc. It is just not worth it.

To main tp object, let alone if one would have to implement it from scratch.

And I'm someone with considerable tp object experience in FPC due to bugfixing the IDE and having done FPC OO before it had classes.

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.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Thaddy on September 30, 2018, 01:05:19 pm
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.
The strongest use-case is still probably KOL over the past 18 years..(Not only for Windows, but as a framework paradigm)
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: mse on September 30, 2018, 02:19:10 pm
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.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: marcov on September 30, 2018, 02:51:11 pm
Do advanced records support inheritance? AFAIK no.

That's what I said. And also you can't derive classes from advanced records. Those are the minor advantages, but I consider them largely theoretical.

Quote
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.

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 "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.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: mse on September 30, 2018, 03:25:54 pm
Quote
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.

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.
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.
Quote
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.
In MSElang the [virtual] object/class header attachment defines it. There is no VMT without [virtual].
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: marcov on September 30, 2018, 03:29:49 pm

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.

I'm currently working on the chm compiler. While not a compiler in the classic sense, it has a lot of binary internal structures, including B+trees. I have dabbled with compilers, interpreters and expression evaluators in the past.

Quote
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 find it annoying even in C++ where you don't have to constantly declare it. The common case should be easy, and shouldn't be hampered by a corner case.)

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.

Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: PascalDragon on September 30, 2018, 04:29:25 pm
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 them (in comparison to global operator overloads) that then can be used inside a generic declaration.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: mse on September 30, 2018, 05:30:13 pm
(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"?
Quote
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.
Quote
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 them
In MSElang operator overloading is also done in objects/classes with the [operator=] method attachment.
https://gitlab.com/mseide-msegui/mselang/wikis/home/mselang_objects#operator
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: ASerge on September 30, 2018, 07:51:21 pm
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.
If we compare records and objects and classes in in FPC now, then

FeatureRecordObjectClass
Encapsulation (combining data and methods + hiding visibility)YesYesYes
InheritanceNoYesYes
Class constrcutor and destrutorYesYesYes
Polymorphism (virtual methods)NoYesYes
Memory allocationStackStackHeap
Operator overload (global)YesYesYes
Operator overload (in type only)YesNoNo
Type helpersYesNoYes
Virtual constructors, class referenceNoNoYes
It should be noted some inconvenience of objects.
If it declares virtual methods, its size increases for storage of VMT (records not containing VMT, size not changed, classes always has VMT, size not changed).
To make virtual methods work, you must define a constructor and call it (the constructor is required for classes).
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: howardpc on September 30, 2018, 08:47:00 pm
A further difference between advanced records and objects/classes is the possibility of advanced records having variant parts (with or without methods).
As far as I can see the keywords "procedure" and "constructor" can be used interchangeably in advanced records. Is there in fact any difference between them in this case?
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: avra on October 01, 2018, 07:05:57 am
If we compare records and objects and classes in in FPC now, then
This nice comparison table should end up in a wiki...
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: 440bx on October 01, 2018, 07:38:17 am
If we compare records and objects and classes in in FPC now, then
This nice comparison table should end up in a wiki...
I concur with the above.  Very nicely done Serge.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Thaddy on October 01, 2018, 08:01:43 am
@ASerge
Don't forget management operators for records. (3.2+)
Also note that advanced records do have a VMT if these are used.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: avra on October 01, 2018, 09:26:11 am
Don't forget management operators for records. (3.2+)
Also note that advanced records do have a VMT if these are used.
Thanks for the update, Thaddy
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: JernejL on October 01, 2018, 12:09:51 pm
So, nowadays, why should I choose advanced records instead of object type?

Record routines in FPC inline better than object methods (from my experience)
Memory alignment control for structures (plus very fast read & write, you can just write and read it to Tstream)
Bit packed records are possible too, when dealing with specific limitations or special projects.
Easier allocation for some very fast purposes (array of records can be allocated with just a simple setlength call)
Faster (no RTL overhead).
No constructors needed in variables, just declare & call routines directly on it.
 
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Awkward on October 01, 2018, 12:44:02 pm
Jernel, objects are like records can be used without constructors, with easy allocation, memory alignment. When records will have inheritance (like in Oberon for example), MAYBE objects will be much less usable. But now objects still have their own area.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: PascalDragon on October 01, 2018, 01:21:19 pm
@ASerge
Don't forget management operators for records. (3.2+)
Also note that advanced records do have a VMT if these are used.
But unlike for objects that is not part of the record "instance", but only part of the Init RTTI metadata, thus per type.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Thaddy on October 01, 2018, 02:37:10 pm
@ASerge
Don't forget management operators for records. (3.2+)
Also note that advanced records do have a VMT if these are used.
But unlike for objects that is not part of the record "instance", but only part of the Init RTTI metadata, thus per type.
Thanks for adding the difference...
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: ASerge on October 01, 2018, 08:11:52 pm
FeatureRecordObjectClass
Encapsulation (combining data and methods + hiding visibility)YesYesYes
InheritanceNoYesYes
Class constrcutor and destrutorYesYesYes
Polymorphism (virtual methods)NoYesYes
Memory allocationStackStackHeap
Operator overload (global)YesYesYes
Operator overload (in type only)YesNoNo
Type helpersYesNoYes
Virtual constructors, class referenceNoNoYes
Variant part (case) as c++ unionYesNoNo
Bitpacked (really packing)YesNoNo

Added a variant part and bitpacked. Thanks @howardpc and @JernejL.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Thaddy on October 01, 2018, 08:38:06 pm
@ASerge
objects can be bitpacked....
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode objfpc}{$endif}
  2. type
  3.   Ttest = bitpacked object
  4.   end;
  5. begin
  6. end.

objects can contain overloads, but the syntax is different and a constructor is required. You need to use the virtual keyword again, "overload" is for classes post TP era. It does the same, however...
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode objfpc}{$endif}
  2. type
  3.   Ttest = bitpacked object
  4.     constructor init;
  5.     procedure testme;virtual;
  6.   end;
  7.  
  8.   Ttest2 = bitpacked object
  9.     constructor init;
  10.     procedure testme;virtual;
  11.   end;
  12.  
  13.   constructor TTest.Init;
  14.   begin
  15.   end;
  16.  
  17.   constructor TTest2.Init;
  18.   begin
  19.   end;
  20.  
  21.   procedure TTest.TestMe;
  22.   begin
  23.   end;
  24.  
  25.   procedure TTest2.TestMe;
  26.   begin
  27.   end;
  28.    
  29. begin
  30. end.

Maybe a bit rusty on TP syntax? This code compiles -Sew
Mode delphi is also OK.

Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: ASerge on October 01, 2018, 10:09:52 pm
objects can be bitpacked....
Carefully read "really packing". In you example bitpacked the same as packed. Packed supported by objects.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: JernejL on October 02, 2018, 07:32:21 am
So, are packed and bitpacked supported on objects?
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Thaddy on October 02, 2018, 07:57:04 am
packed is supported.
bitpacked is at least accepted as valid syntax for objects. I have to test if it does more than just packed based on packsettings 1.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Thaddy on October 02, 2018, 09:27:33 am
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.
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode objfpc}{$endif}
  2. type
  3.   TByteBitsRec = bitpacked record
  4.     Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7: Boolean;
  5.   end;
  6.  
  7.   TByteBitsObj = bitpacked object
  8.     Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7: Boolean;
  9.   end;
  10.  
  11.   TEmptyRec = bitpacked record
  12.   end;
  13.  
  14.   TEmptyObj = bitpacked object
  15.   end;
  16.  
  17. var
  18.   a:TByteBitsRec;
  19.   b:TByteBitsObj;  
  20.   c:TEmptyRec;
  21.   d:TEmptyObj;
  22. begin
  23.   writeln(SizeOf(a)); // 1 byte
  24.   writeln(SizeOf(b)); // 8 bytes
  25.   writeln(SizeOf(c)); // 0 bytes
  26.   writeln(SizeOf(d)); // 0 bytes
  27. end.

Which makes you wonder if that is not a bug (either bitpack objects or do not accept the syntax)
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: 440bx on October 02, 2018, 02:32:56 pm
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.

Either the compiler should reject "bitpacked" in an object declaration or, the documentation should be updated to show it is acceptable.

NOTE: Free Pascal Reference Guide for version 3.0.2 (February 2017)

Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Thaddy on October 02, 2018, 02:40:53 pm
I already filed a bug against the issue. I drew the same conclusion and there really aren't any docs about it (including trunk docs). Unless you count ASerge observation as documentation. 8-) Which some do. Anyway he was right and it was easy to prove.

That leaves management operators to be filled in to the matrix.
And that classes are a pointer-to-structure and not a structure itself.
And that objects can mimic virtual constructors (for that reason) with constructing functions returning a pointer to object. (Like in KOL)
And some memory management oversights for classes like initinstance
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: 440bx on October 02, 2018, 06:41:00 pm
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.)
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Thaddy on October 02, 2018, 07:24:32 pm
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.
That does not mean that would not exist.....
I almost monthly report on omissions, unclear or wrong fragments of documentation. This is usually very quickly repaired or explained.
"There are more things in heaven and earth, Horatio,  Than are dreamt of in your philosophy." read: documentation can cover...
- Hamlet (1.5.167-8), Hamlet to Horatio
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: skalogryz on October 02, 2018, 07:50:35 pm
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)
Quote
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.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Thaddy on October 02, 2018, 08:50:08 pm
Which is - by all means - incorrect, or at least imprecise - for the issue at hand.
An object can not be / is not bitpacked.
There is still an open issue regarding this on Mantis from 8 years ago.

Doc fix is OK with me, but it should be a compiler fix.

That said: for most this will remain a minor issue. To me it is not.(KOL, although I do not use that much, let alone are involved anymore)
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: 440bx on October 02, 2018, 09:57:57 pm
It's unfortunate that the compiler allows "bitpacked" in an object declaration as it may lead a programmer to believe the object is actually bitpacked when it isn't.

If the compiler allows the use of "bitpacked" when declaring an object then the documentation, i.e, the Free Pascal Reference Guide, should clearly state that its presence has no effect on the object's fields.  In that case, the documentation should also be updated to reflect that the use of "bitpacked" is allowed in an object declaration (it currently doesn't.)




Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: jwdietrich on February 17, 2021, 09:35:27 pm
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.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: egsuh on February 20, 2021, 02:19:29 am
Quote
Feature                                    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.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: ASBzone on March 04, 2021, 04:34:20 pm
The very first line of ASM code Is missing with the 3.2.0.

Hey, @jamie.  The two asm snippets you posted, one for 3.0.4 and one for 3.2.0, appear to be identical.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: jamie on March 04, 2021, 06:18:18 pm
I did not post the 3.2.0 output here. Those are both 3.0.4 64 bit.

What i was saying is the first line of asm that u see there is missing from the 3.2.0 output.

And because of that the inline proxy over to a procedure fails with 3.2.0

No worries , i moved that project to delphi and most likely will do the same for others when 3.0.4 goes dead
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Blade on March 23, 2021, 10:17:30 am
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.

True, in terms of Class-based OOP.  Clascal was a play on words, "Pascal with classes".  Kind of like the supposedly original name of C++, C with classes.  But, it arguably should not be ignored that many programmers and programming languages have used objects without classes.  Some examples of this are JavaScript and Lua, which are Prototype-based OOP languages, and newer languages like Go (Golang) which avoids Class-based OOP.  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.

To add to the fun, there is of course C and structs, but arguments on whether or not that can even be considered OO (or can be implemented like such) can make you dizzy, often the arguments center around if having objects without methods and/or classes is really OOP.  Arguments along those lines can become quite philosophical, where people believe that nouns and verbs (data and functions) should remain separate from each other.  Additionally, you can have objects without classes that are data only, inherit, and/or are encapsulated, but the implementation becomes a sticking point.  There are competing views as to what exactly OO is.

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.  I think a reflection of such is why we have this interesting juggling of advanced records, objects, and classes in our language.  I think people have different comfort levels and views about how deep to go or how often they need Class-based OOP.  The great thing about Object Pascal/Free Pascal, is that as a hybrid language, we have options.  Arguably, OOP is done more gently and optionally in our language.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: marcov on March 23, 2021, 02:46:33 pm
  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.

Dot notation vs -> is a C++ problem. It doesn't have anything to do with class based OOP, since the language can just autoderef, like many languages do (include FPC in some modes)

Quote
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.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Blade on March 23, 2021, 03:39:46 pm
Quote
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. 
Quote
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.

I have a tremendous amount of respect and empathy for developers, and I'm quite sure two OO models is not something that many would find agreeable.  In fact, I'm at peace with how Class-based OOP was implemented in Free Pascal/Delphi. 

But, it doesn't change the fact that other languages took different paths and it's working for them or that many programmers are not comfortable with the conventional implementations of Class-based OOP, having fragmented data merged with methods (the nouns should be separated from verbs debate), or with particular pillars of OOP like inheritance (which also gets into the composition versus inheritance debates) and encapsulation.  Even the creator of Pascal (Niklaus Wirth) appeared to give some push back on the various pillars and use cases of conventional OOP, where they can be different useful alternatives in various situations.  Of course in certain cases, the full glory of Class-based OOP (with inheritance, encapsulation, polymorphism, etc...) is exactly the right answer.  Just not always the answer.

In Object Pascal circles, it appears that records and advanced records are kind of like viable alternatives.  If you look at many of the criticisms of conventional OOP, you can see that records and advances records can also be a way to provide more philosophically agreeable alternatives to many.  That is: you can separate nouns from verbs (unwanted coupling of fragmented data with methods/among multiple classes), choose composition over inheritance (or choose explicit inheritance with records when wanted), rely more on using units as way to extend program functionality, a reduction in Class-based OOP specific syntax/keeping smaller programs simple, easier troubleshooting, etc... As for "old school Objects", arguably they can be seen as a simpler way to deal with OOP or offer some specifically wanted advantage.

I'm of the opinion that the situation works for many Object Pascal programmers, where they can choose suitable options of their liking.  Definitely not saying that such a situation would be viewed as optimal by most developers (who are looking at things at a larger scale than most), but forcing only a certain path might not be helpful to many either.  Perhaps that's partly how Borland/Embarcadero put Delphi into a messy situation with advanced records and their implementations of OOP.  Don't see any easy answers.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: devEric69 on October 20, 2021, 05:52:05 pm
Quote
Feature                                    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.

I'm studying advanced records. But I'm reluctant about their usefulness compared to classes especially when I read things like the ones above, concerning their memory management. So, to clarify, I've 2 questions - concerning advanced records - which are:
- 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?
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Warfley on October 20, 2021, 08:22:28 pm
Records are (unlike classes) not pointers, but describe actual memory blocks.

When using a record you need to make sure where it is allocated. If it's a global variable, it is located at the DATA segment, if it's a local variable it's on the stack. You can also place it on the heap but then you need to access it via pointers.
The memory of the stack and global variables is always freed (stack when the function returns, global variables when the program is killed).

Classes are always located on the heap and thereby behave like records if you use pointers. Basically class types are pointers in disguise. They can only be placed on the heap which makes them require manual memory management.

This has some implications. When assigning a class type, you just copying the pointer, it is just a reference to the same memory location:
Code: Pascal  [Select][+][-]
  1. c1, c2: TMyClass;
  2. begin
  3.   c1 := TMyClass.Create;
  4.   c2 := c1;
  5.   c2.A := 'foo';
  6.   WriteLn(C1.A); // is Foo
  7.   c2.Free; // same as c1 therefore c1 is freed
With records you are actually copying the data:
Code: Pascal  [Select][+][-]
  1. r1, r2: TMyRecord;
  2. begin
  3.   r1 := TMyRecord.Create('Foo'); // initialze A with 'Foo'
  4.   r2 := r1;
  5.   r2.A := 'Bar';
  6.   WriteLn(r1.A); // Shows 'Foo' because r2 is a copy
But with the use of Pointers this is still rather similar:
Code: Pascal  [Select][+][-]
  1. type PMyRecord = ^TMyRecord;
  2. var r1, r2: PMyRecord;
  3. begin
  4.   New(r1, 'Foo'); // calls create with argument 'Foo'
  5.   r2 := r1;
  6.   r2^.A := 'Bar';
  7.   WriteLn(r1^.A); // Prints 'Bar' as both reference the same record
  8.   Dispose(r2); // Same memory as r1 therefore both are freed

So I think it is better to not think of records and classes as fundamentally different with respect to memory management, but classes are just pointers to datastructures not so disimilar to records, but they are just hiding it.

But, the Destructor does not only do memory management, but also calls the destroy function which can contain arbitrary code. To simulate that you can simply add a destroy function to the record, basically the same effect.

Note, you can also emulate class like syntax with some modeswitches:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. {$ModeSwitch advancedrecords}
  3. {$ModeSwitch autoderef}
  4.  
  5. type
  6.   PMyRec = ^TMyRec;
  7.  
  8.   TMyRec = record
  9.   private
  10.     FA: String;
  11.   public
  12.     class function Create(const AValue: String): PMyRec; static;
  13.     procedure Destroy;
  14.     procedure Free;
  15.  
  16.     property A: String read FA write FA;
  17.   end;
  18.  
  19. class function TMyRec.Create(const AValue: String): PMyRec;
  20. var
  21.   Self: PMyRec absolute Result;
  22. begin
  23.   New(Self);
  24.   Self.A := AValue;
  25. end;
  26.  
  27. procedure TMyRec.Destroy;
  28. begin
  29.   Dispose(PMyRec(@Self));
  30. end;
  31.  
  32. procedure TMyRec.Free;
  33. begin
  34.   if Assigned(@Self) then
  35.     Destroy;
  36. end;
  37.  
  38. var
  39.   r1, r2: PMyRec;
  40. begin
  41.   r1 := TMyRec.Create('Foo');
  42.   r2 := r1;
  43.   r2.A := 'Bar';
  44.   WriteLn(r1.A); // Prints Bar because this is just a pointer
  45.   r2.Free;
  46. end.
It's not perfect because you can't add the class method Create to PMyRec (which is how class constructors work) so you have to use TMyRec for creation but PMyRec variable type, but aside from that, this is pretty much all what classes do.
From a syntactic level classes are just advanced records or objects with {$ModeSwitch autoderef}  activated.

Thats why I personally think that introducing classes was a terrible idea by Borland. With respect to memory management, they are just like objects but worse as you can simply do less with them.
If you ask me, the best solution would be to just throw classes away (or deprecate them) and give all their functionality to advanced records, making both classes and objects only be there fore legacy code compatibility and having with the new advanced records a datatype model which is simply more powerful than classes thanks to more options with respect to memory managment.

And the features of autoderef could be incorporated right into the syntax:
Code: Pascal  [Select][+][-]
  1. type
  2.   PMyRec = autoderef ^TMyRec;
  3.   TMyRec = record
  4.     ...
  5.   end;
  6.  
  7. var
  8.   r: PMyRec;
  9. begin
  10.   r := PMyRec := PMyRec.Create('Foo'); // autoderef also applies to class functions
  11.   r.A := 'Bar';
  12.   r.Free;
  13. end;
There wouldn't even be much difference to current classes on a syntactical level (if typing a few ^ is to hard for people)
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: PascalDragon on October 21, 2021, 09:05:46 am
- 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?

Unlike for classes a constructor of a record is not also an allocator. Essentially it's a function in the form of class function Create(...): TRecord; static; where the return value is accessed with Self instead of Result. Nothing else special is done there.

- as there are no destructors for such advanced records, are they deallocated automatically? Whether they are in the stack or in the heap?

Advanced records are just like ordinary records with the added benefit that you can add visibility sections, methods, properties and operators to them. Otherwise they behave exactly the same.

The ability to add operators is the main advantage of advanced records: these operators can be picked up by generics, while global operator declarations can only be picked up if they were available during the time the generic itself was declared and not when it is specialized.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: devEric69 on October 21, 2021, 10:11:09 am
• Thanks to @Warfley (nb: for me, an object is a class instance; I may not have posted my question in the right thread, talking from "old OBJECT") and thanks to @PascalDragon for their answers.

I've found an example from @ASerge...:

Code: Pascal  [Select][+][-]
  1.     {$APPTYPE CONSOLE}
  2.     {$IFDEF FPC}
  3.       {$MODE OBJFPC}
  4.       {$MODESWITCH ADVANCEDRECORDS}
  5.     {$ENDIF}
  6.      
  7.     type
  8.       PMyType = ^TMyType;
  9.       TMyType = record
  10.         constructor Init(AValue: Integer);
  11.       end;
  12.      
  13.     constructor TMyType.Init(AValue: Integer);
  14.     begin
  15.       Writeln('Init ', AValue);
  16.     end;
  17.      
  18.     var
  19.       P: PMyType;
  20.     begin
  21.       New(P, Init(123)); // or P := New(PMyType, Init(123));
  22.       Dispose(P);
  23.       Readln;
  24.     end.
  25.  

...which illustrates the response from @PascalDragon i.e. they are indeed records like the others records from the memory management point of view: we always have to call New and Dispose, if we want to allocate them inside the heap. I had a doubt because of the constructor keyword. 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). And I've well understood the advanced record's advantages with their class operators (like =, <, >).


• Having understood  the memory management of the advanced records (same way of managing the memory as the "old" ones), leads me to the following question: if I want to make a TAdvancedRecList = specialize TFPGList< TAvancedRecord > containing advanced records allocated in the heap (so, using New(pAdvRecFoo);), do I have to declare...:

Code: Pascal  [Select][+][-]
  1. {$MODESWITCH ADVANCEDRECORDS}
  2.  
  3. uses
  4.   sysutils, fgl;
  5.  
  6. type
  7.   TAdvRecord = record
  8.     field1: string;
  9.     field2: integer;
  10.     class operator = (r1, r2: TRecord): Boolean;
  11.     constructor Create(f1: string; f2: integer);
  12.   end;
  13.  
  14.   TAdvRecList = specialize TFPGList<TAdvRecord>;

...or do I have to declare...


Code: Pascal  [Select][+][-]
  1. {$MODESWITCH ADVANCEDRECORDS}
  2.  
  3. uses
  4.   sysutils, fgl;
  5.  
  6. type
  7.   PAdvRecord = ^TAdvRecord;
  8.   TAdvRecord = record
  9.     field1: string;
  10.     field2: integer;
  11.     class operator = (r1, r2: TRecord): Boolean;
  12.     constructor Create(f1: string; f2: integer);
  13.   end;
  14.  
  15.   TAdvRecList = specialize TFPGList<PAdvRecord>;

... in order to store the advanced record's pointers (previously allocated in the heap with  New(pAdvRecFoo);)?

This question, this doubt comes from this _post_ (https://forum.lazarus.freepascal.org/index.php/topic,50112.msg365327.html#msg365327), where the Pointer type on its advanced record Type is not used. So, I guess that this example uses a specialized list which is created in the same cloture \ namespace \ calls stack, as the one (calls stack) of the unallocated records it is storing.



Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: devEric69 on October 21, 2021, 03:08:58 pm
I found the answer in this _post_ (https://forum.lazarus.freepascal.org/index.php/topic,33508.msg217338.html#msg217338):

Quote from: Thaddy
>
> 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.

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).
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: Warfley on October 21, 2021, 07:55:25 pm
The thing with records is, you have complete control when and where to place them. So that you need to allocate memory and use pointers is not quite correct. Of course TFPGMap will internally do the memory allocation, but generally speaking you can use records on any memory

For example, you can easiely make a List that is on the stack with records:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$ModeSwitch advancedrecords}
  5.  
  6. type
  7.  
  8.   { TStackList }
  9.  
  10.   generic TStackList<T, const MaxCount: SizeInt> = record
  11.   private type PT = ^T;
  12.   private const Capacity = MaxCount * SizeOf(T);
  13.   private
  14.     FData: Array[0..Capacity - 1] of Byte;
  15.     FLength: SizeInt;
  16.  
  17.     function GetItem(AIndex: SizeInt): T;
  18.     procedure SetItem(AIndex: SizeInt; const AValue: T);
  19.   public
  20.     constructor Create;
  21.     procedure Destroy;
  22.  
  23.     function Add(constref AValue: T): SizeInt;
  24.     procedure Delete(AIndex: SizeInt);
  25.  
  26.     procedure Clear;
  27.  
  28.     property Items[AIndex: SizeInt]: T read GetItem write SetItem; default;
  29.     property Length: SizeInt read FLength;
  30.   end;
  31.  
  32.  
  33. constructor TStackList.Create;
  34. begin
  35.   FLength := 0;
  36. end;
  37.  
  38. procedure TStackList.Destroy;
  39. begin
  40.   Clear;
  41. end;
  42.  
  43. function TStackList.Add(constref AValue: T): SizeInt;
  44. begin
  45.   if FLength >= MaxCount then Exit(-1);
  46.   Result := FLength;
  47.   Initialize(PT(@FData)[Result]);
  48.   Items[Result] := AValue;
  49.   Inc(FLength);
  50. end;
  51.  
  52. procedure TStackList.Delete(AIndex: SizeInt);
  53. begin
  54.   if AIndex >= FLength then Exit;
  55.   Finalize(PT(@FData)[AIndex]);
  56.   Dec(FLength);
  57.   Move(PT(@FData)[AIndex + 1], PT(@FData)[AIndex], FLength - AIndex);
  58. end;
  59.  
  60. procedure TStackList.Clear;
  61. begin
  62.   while FLength > 0 do
  63.     Delete(FLength - 1);
  64. end;
  65.  
  66. type
  67.  
  68.   TTestRec = record
  69.   A, B: String;
  70.   constructor Create(const AA: String; const AB: String);
  71.   end;
  72.  
  73. constructor TTestRec.Create(const AA: String; const AB: String);
  74. begin
  75.   A := AA;
  76.   B := AB;
  77. end;
  78.  
  79. type
  80.   TTestList = specialize TStackList<TTestRec, 1024>;
  81.  
  82. var
  83.   Lst: TTestList;
  84.   i: Integer;
  85. begin
  86.   Lst := TTestList.Create;
  87.   try
  88.     Lst.Add(TTestRec.Create('Foo', 'Bar'));
  89.     Lst.Add(TTestRec.Create('FooBar', 'BarFoo'));
  90.     for i := 0 to Lst.Length - 1 do
  91.       WriteLn('Entry: ', i, 'A: ', Lst[i].A, ', B:', Lst[i].B);
  92.   finally
  93.     Lst.Destroy;
  94.   end;
  95. end.

Here, because it is located on the stack (or to be more precise, a global variable), we don't need to do *any* memory allocation. That said, we still need to perform initialization and cleanup (in Add and Delete).

If we had alloca, it would even be possible to have this list dynamically growing.

To sum it up, you should think about allocation and initialization as different things. It doesn't matter how the memory for your record was allocated as long as you initialize and finalize properly your code can be completely independent from allocation
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: devEric69 on October 21, 2021, 08:07:54 pm
Wow! Thank you, for this programming lesson.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: SymbolicFrank on October 22, 2021, 12:46:50 pm
A class / object / advanced record is basically a block of memory with an index to show where the different parts reside. Methods are just functions / procedures that have an invisible @self pointer as first parameter. So, nothing is stopping you to allocate simple records on the stack and access them through pointers. In the past, before classes existed, I put all of the parts in linked lists, so it was easy to inherit and with an optional index to access the larger ones faster. Which is basically what a modern class is, although the compiler magic hides the pointers and packs them into arrays.
Title: Re: What is the difference between the new ADVANCED RECORD and the old OBJECT?
Post by: PascalDragon on October 22, 2021, 03:51:43 pm
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).

You can name the constructor method any way you want, even for classes. The only exception is if you want to override an existing constructor then you need to use the same name, but otherwise you're free to use Init in a class as well.

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).

That management indeed has nothing to do with advanced records or not, it's simply related to whether you use e.g. AnsiString, Variant or IInterface.
TinyPortal © 2005-2018