I used Abstract to get around the Generic type 'bug', is there a neater solution lazarus / 62-General ---------------------------------------------------------------------- old_DOS_err · 2025-01-29 18:28 Hi, Currently doing a shell program (better version of Explorer, for certain areas, for example a better search, including ranges for video length, file size, and date). Have done the search and just doing the sort. I wrote a Generic binary tree sort, nice and fast (used a simple linked list method, so never need to move the data, just insert the new data). In the tests I used all simple types, including string, but in the shell program I use a record for the file info. That is when I ran into the standard Generics type problem. I use 2 virtual functions to test if the new value was higher or lower (could have just used 1, but neater with 2, for ascending and descending). So for is_new_higher, I compare 2 values sent in, e, existing, and n, new, Result := n > e; But when I use the record type, even though the is_new_higher function is virtual, the compiler halts at the original comparison and gives the type problem message. I consider this a bug, because when the code runs, this code will never run for that type, which is what the virtual SHOULD be doing. For example, if I commented out the original code, eg //Result := n > e; and used just the record type with the virtual method to replace the original, the program would both compile and run fine. (I have used complicated pointer methods in the past to hide the type, but that would not be suitable nor desirable here). Yes, I know there are those that say if one has to make exceptions for data types, then maybe generics isn't the right way. I have a build array (a linked list with a number system overlaid so it behaves like an array, used to create an array on the fly with no idea how many elements), that is perfect for generics, as never have to do anything with the data other than move it around. But I'd say sort is also ideal for generics, but the type issue does make it more difficult to implement that, since at some point need to compare 2 values. I also believe that part of pascal's limits are due to the choice to do a 1 pass compiler (I wrote a simple program language for my final year project at uni, very long time ago, Turbo Pascal 6, it was 3 pass, OTT maybe, but zero issues with forward references), so lower parts, like units, must be compiled without any idea of the actual types used further up. I did skim the Michaël Van Canneyt pdf document on generics, to be honest I struggled to understand the text and his end solution ended up looking more clunky than mine, going into interfaces and class vars. Anyway, I got a fairly simple solution, but as I say, I still think it is clunky. I'd be grateful if anyone knows a more elegant method. This is a stipped down and moderated example of that, I hope this makes sense. 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 Program general_testing;{$mode objfpc}{$H+}Uses  Classes, SysUtils; Type   Generic test_sort_class_Abstract< T > = Class  // any new compare method must use this - changed to T just to fit in with the more usual style, I often use arr_type, old school        Procedure is_new_higher( e, n : T ); Virtual; Abstract;  // this works but I consider it a stupid way to go about it  End;   Generic test_sort_class< T > = Class( Specialize test_sort_class_Abstract< T > )  // this should be the base object - found this method on this forum from an answer by Thaddy        Procedure is_new_higher( e, n : T ); Override;  // in original, this was just Virtual; which I did it this way precisely to allow for more complex types  End;   // i like to place useful types below my generic classic, here just placed Word, see Word test below  _test_sort__Word_ = Specialize test_sort_class< Word >;  // can't remember where I found this method came from, probably this forum  test_sort__Word = Class( _test_sort__Word_ );   // simple extended, silly example but fits with original type - here going to test the absolute of the value  _test_sort__Int16_ = Specialize test_sort_class< Int16 >;  // because this type fits with the original, using just the defined class, but could have used the Abstract  test_sort__Int16 = Class( _test_sort__Int16_ )        Procedure is_new_higher( e, n : Int16 ); Override;  End;   // now add a record type  simple_record_type = Record        x, y : Byte;  // emulate my file info record, the field are irrelevant  End;   _test_sort__rec_ = Specialize test_sort_class_Abstract< simple_record_type >;  // note this has to use the Abstract one  test_sort__rec = Class( _test_sort__rec_ )        Procedure is_new_higher( e, n : simple_record_type ); Override;  End; // Word Procedure test_sort_class.is_new_higher( e, n : T );  // in the sort this is Boolean function, simply Result := n > e;  Begin        If n > e Then  // this is where the original fell over in compile, even tho this code would never run when the record type was used      WriteLn( 'test_sort_class: new is higher' );  // didn't bother with an Else, just needed to see it called the right one  End; Procedure test_type_problem_Word;  Var        t : test_sort__Word;  // here is the useful type        n, e : Word;   Begin        t := test_sort__Word.Create;         n := 32;  // new value being added      e := 12;  // existing value        t.is_new_higher( e, n );       FreeAndNil( t );  End; // Int16 Procedure test_sort__Int16.is_new_higher( e, n : Int16 );  Begin        If Abs( n ) > Abs( e ) Then        WriteLn( 'test_sort__Int16: new is higher' );  End; Procedure test_type_problem_Int16;  Var        t : test_sort__Int16;  // here is the useful type        n, e : Int16;   Begin        t := test_sort__Int16.Create;         n := -32;          e := -12;          t.is_new_higher( e, n );         FreeAndNil( t );  End; // record - just using field x here, which emulates sorting the field// (note the whole record must be used in the shell, as I use parallel arrays and a translate index system) Procedure test_sort__rec.is_new_higher( e, n : simple_record_type );  Begin      If n.x > e.x Then  // the code that will replace the original and in my opinion the compiler should NOT give an error since it knows this is here        WriteLn( 'test_sort__rec: new is higher' );  End; Procedure test_type_problem_rec;  Var        t : test_sort__rec;  // here is the useful type        n, e : simple_record_type;   Begin        t := test_sort__rec.Create;         // just using x, it was just to get the mechanics        n.x := 32;  // new value being added      e.x := 12;  // existing value        t.is_new_higher( e, n );       FreeAndNil( t );  End; Begin  test_type_problem_Word;  test_type_problem_Int16;  test_type_problem_rec;   WriteLn; WriteLn('Finished...'); ReadLn;End.  I look forward to any responses. As a quick aside, don't suppose anyone knows if there are any plans to allow virtual inline at some point? I did try and looked online, even though already very fast, would be the icing on the cake. Phil Program Details: Lazarus: 3.4 (date: 2024-05-25)   FPC: 3.2.2   Version: Win64 Operating system: Windows Pro 10, 22H2 Hardware: Intel Core i5-3570K CPU, 3.40GHz, RAM: 8GB, 64 bit