Advice about switching from Extended Records to Classes/Objects lazarus / 62-General ---------------------------------------------------------------------- ad1mt · 2024-02-08 16:39 I'm designing a library for new big integer data types, and implemented them with extended advanced records. While working on the code, I've hit some weird problems. I managed to get the code working, but sometimes I could not understand the cause. So I'm thinking I should change the code to implement the new data types using classes/objects instead of extended records. I've not really done much O.O. coding, so before starting, I would like some advice about whether switching to classes/objects... 1. Will make my library more reliable/robust? 2. Will it be easier or harder to make my code thread-safe? 3. Will it be easier or harder for my new data types to be used from within classes in other O.O. code? 4. Will it still be possible to use my data types exactly the same way as the native integer types?  (i.e. without having code all the O.O. stuff to do with constructors/destructors etc). 5. Any other warnings/advice? I've got & read the Cantu book "Object Pascal Handbook", so I don't need an O.O. programming tutorial. But I would like the wisdom of a Free Pascal expert on these questions. Thanks. ---------------------------------------------------------------------- Thaddy · 2024-02-08 16:48 If you have a flat architecture use records and advanced records. If you want OOP - specifically inheritance -use either objects or classes. That has been the case for well over 30 years so what exactly is the part you do not understand? Ok, advanced records are a bolt-on from much later years, but only covers the inclusion of code that is tied to that specifically defined record type. ---------------------------------------------------------------------- 440bx · 2024-02-08 18:33 I'm going to presume that by "extended records" you mean "advanced records". If you've run into weird problems with advanced records, there is no reason to believe that moving to objects or classes will make those weird problems vanish.  Moreover, if your experience with objects and/or classes is limited then you'll likely run into a lot of weird problems with those mostly due to your lack of experience coding using them. As far as your questions.... 1. No.  the reliability will at best remain the same. I say, at best, because if your experience coding with objects and/or classes is limited then it's likely the end result will be less reliable. 2. with classes, likely harder because those are allocated on the heap and heaps can be used by multiple threads simultaneously, therefore, you may need to use synchronization (to be fair, that depends on what you're doing.)  with objects, it depends, if they reside on a heap then the potential problem is the same as when using classes, if they are on the stack then it isn't a problem.  with advanced records and objects, as long as they are allocated on the _stack_ then you normally don't have to worry about thread synchronization (since each thread has its own stack.) 3. it might be easier for OO code to use your library but, the additional ease is truly minimal.   too minimal to be taken into account in making the decision. 4. No.  Once you go OO you pretty much force any code that wants to use your library to be OO.  Note that the converse is not true.  If your library only uses advanced records, it can be used by OO code and non-OO code just the same. 5. Yes.  If you go with the OO solution and would like to provide your functions in a DLL then it can be tricky if your code needs to allocate memory.  If memory is allocated in the DLL and also in the app that is using your code then, there are two (2) memory managers at work and sometimes, ensuring they don't step over each other's toes can be tricky. Piece of advice: you mentioned you're considering objects/classes because you've run into weird problems with your code, the advice is, before doing anything at all, figure out the root cause of the problems.  IOW, the problems should no longer be "weird" because things you _understand_ are no longer "weird".  _After_ you fully understand why your code behaves in whatever way it does then and only then you are in a position of deciding changes like the one you meantioned. HTH. ---------------------------------------------------------------------- Curt Carpenter · 2024-02-08 20:24 Take a look at this thread:  https://forum.lazarus.freepascal.org/index.php?topic=57155.0 .  I found Structures in Object Oriented Programming in Free Pascal and Lazarus by Zsolt Szakály (linked to in the thread) to be very worthwhile in addressing my own questions in this area. ---------------------------------------------------------------------- Thaddy · 2024-02-09 06:54 Quote from: 440bx on February 08, 2024, 07:33:52 pmI'm going to presume that by "extended records" you mean "advanced records". Those terms are commonly used interchangeably. ---------------------------------------------------------------------- ad1mt · 2024-02-09 12:06 Quote from: Curt Carpenter on February 08, 2024, 09:24:24 pmI found Structures in Object Oriented Programming in Free Pascal and Lazarus by Zsolt Szakály (linked to in the thread) to be very worthwhile in addressing my own questions in this area. Thank you for this, it looks very interesting. ---------------------------------------------------------------------- Warfley · 2024-02-09 13:03 Quote from: ad1mt on February 08, 2024, 05:39:13 pm1. Will make my library more reliable/robust? As big number libraries are typically something that does not benefit from inheritance, I don't think so. Infact with classes and objects you need to call constructors and destructors explicetly, making it harder to use. Also probably your performance is going to suffer. Quote from: ad1mt on February 08, 2024, 05:39:13 pm2. Will it be easier or harder to make my code thread-safe? Definitely harder. Thread safety is an issue when data is shared accross multiple threads. This requires references. When you want to reference a record you must explicetly take the pointer of it, meaning most of the time you will be working on unique copies, which are by definition thread safe. Classes on the other hand are always references, so when you want to make sure the uniqueness of an instance, you need to go through extra hoops (e.g. creating a new object and calling assign). Quote from: ad1mt on February 08, 2024, 05:39:13 pm3. Will it be easier or harder for my new data types to be used from within classes in other O.O. code? Harder. Extended records can be managed, meaning you don't need to write initialization/construction and finalization/destruction code when using those. For objects and classes you must do so explicitly, adding extra code for using them (which is also an additional source for errors) Quote from: ad1mt on February 08, 2024, 05:39:13 pm4. Will it still be possible to use my data types exactly the same way as the native integer types?  (i.e. without having code all the O.O. stuff to do with constructors/destructors etc). Nope, you always must write .Create and .Free (or .Destroy). Also you can't overload operators Quote from: ad1mt on February 08, 2024, 05:39:13 pm5. Any other warnings/advice? What I've wrote above is all generally true, but there is a workaround. Using COM interfaces. This is how GMP is implemented. This makes the usage side easy, but as a tradeoff you need to double all the class definitions as COM interfaces to be usable. So implementation is going to get much messier, but you can use operator overloading and don't need manual memory management. Example on how you can use the GMP (from memory, may be slightly wrong) Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses gmp; var  a, b, c: MPInteger;begin  a := 168203;  b := 65213;  c := a ** b;  WriteLn(String(c));end; ---------------------------------------------------------------------- Nitorami · 2024-02-09 17:44 QuoteExample on how you can use the GMP (from memory, may be slightly wrong) WHAT ? How does that work, and where is it documented ? Whenever I used GMP, I always struggled with awkward constructs for simple tasks, like this Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   mpz_init (a1);  mpz_init (b1);  mpz_init (p);  mpz_set_ui(a1,a);  mpz_ui_pow_ui(b1,2,b*r); //b1 = 2^(b*r) ---------------------------------------------------------------------- Warfley · 2024-02-09 18:51 Been available for many years but documenting it is still a todo on the wiki: https://wiki.lazarus.freepascal.org/gmp#Operators But pretty much all the standard operators, as well as most casts to common datatypes (string, integer, double) are supported. It's actually ma favorite example on when automatic reference counting is great, and how you could utilize it for your own types