Lazarus

Programming => General => Topic started by: Shpend on December 08, 2019, 02:08:49 am

Title: Type "TMyType" is not completly defined
Post by: Shpend on December 08, 2019, 02:08:49 am
Hi all,

In short I would like to be able to do the following:

Code: Pascal  [Select][+][-]
  1. TMultiSet<T> = record
  2.        fField: byte;
  3.        value: TMultiSet<T>;
  4.      end;  
  5.  

//Error: Type "TMultiSet<T> " is not defined yet

Is there any chance of making this possible and if so, how am I able to work around

Thx in advance!
Title: Re: Type "TMyType" is not completly defined
Post by: 440bx on December 08, 2019, 02:17:53 am
Hi all,

In short I would like to be able to do the following:

Code: Pascal  [Select][+][-]
  1. TMultiSet<T> = record
  2.        fField: byte;
  3.        value: TMultiSet<T>;
  4.      end;  
  5.  

//Error: Type "TMultiSet<T> " is not defined yet

Is there any chance of making this possible and if so, how am I able to work around

Thx in advance!
Answer to first question: making it possible ? the answer is no because that record definition is recursive and the compiler cannot determine at any time what the size of the record is.

Answer to second question: how to work around it: define a pointer to a TMultiSet<T> (presumably PMultiset) and use that as the type of the "value" field.

HTH.
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 08, 2019, 02:30:11 am
Hi, @440bx :

I tried ur suggestion, with this:

Code: Pascal  [Select][+][-]
  1.  
  2.     generic PMultiSet<T> = ^TMultiSet<T>;
  3.  
  4.      generic TMultiSet<T> = record
  5.        index: byte;
  6.        value: PMultiSet<T>;
  7.      end;  
  8.  

sry im kinda new to generics and stuff would you mind showing me a code example, i get only type errors :/
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 08, 2019, 02:37:35 am
and btw i get (attachment)error when I declare (attachment)code:

Title: Re: Type "TMyType" is not completly defined
Post by: 440bx on December 08, 2019, 02:37:43 am
Hi, @440bx :

I tried ur suggestion, with this:

Code: Pascal  [Select][+][-]
  1.  
  2.     generic PMultiSet<T> = ^TMultiSet<T>;
  3.  
  4.      generic TMultiSet<T> = record
  5.        index: byte;
  6.        value: PMultiSet;
  7.      end;  
  8.  

sry im kinda new to generics and stuff would you mind showing me a code example, i get only type errors :/
I think that with the following change your declaration should work
Code: Pascal  [Select][+][-]
  1. PMultiSet = ^TMultiSet<T>;
and the field "value" should be declared as
Code: Pascal  [Select][+][-]
  1. value : PMultiSet;
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 08, 2019, 02:41:47 am
I tried your example mate, but sadly I get also here a type error:
(attachment!)

And it actually is correct, since he cant know what <T> should mean without  the generic keyword and/or the brackets in PMultiSet<T> i would assume..

but did you see also the attachment above: it says:

"Error: Internal error: 20010001" or the like
Title: Re: Type "TMyType" is not completly defined
Post by: 440bx on December 08, 2019, 02:49:32 am
I tried your example mate, but sadly I get also here a type error:
(attachment!)

And it actually is correct, since he cant know what <T> should mean without  the generic keyword and/or the brackets in PMultiSet<T> i would assume..

but did you see also the attachment above: it says:

"Error: Internal error: 20010001" or the like
The internal error should not be happening, that should probably be considered a bug in FPC but, that is a determination better left to the developers.

I know what you're trying to do and since I rarely use generics I'm not getting the syntax right.  I'll be back in a few minutes after I figure out the correct way.
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 08, 2019, 02:59:47 am
I would thank you alot, since i just cant get around it myself currently ..
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 08, 2019, 03:29:50 am
I have an inner feeling that this doesnt work right now in fpc, hopefully im wrong about this
Title: Re: Type "TMyType" is not completly defined
Post by: 440bx on December 08, 2019, 03:51:33 am
I thought I knew the answer to your question but, I don't. 

The following does NOT work but, I believe it should work
Code: Pascal  [Select][+][-]
  1. type
  2.   // Error: Generics without specialization cannot be used as a type for a variable
  3.  
  4.   PMultiSet = ^TMultiSet;
  5.   generic TMultiSet<T> = record
  6.     next : PMultiSet;
  7.     data : T;
  8.   end;
  9.  
I don't think the pointer declaration should require the generic type to be specialized.

Hopefully, someone else can answer your question.
Title: Re: Type "TMyType" is not completly defined
Post by: bytebites on December 08, 2019, 05:07:57 am
Delphi mode
Code: Pascal  [Select][+][-]
  1.   TMultiSet<T> = record
  2.          fField: byte;
  3.          value: ^TMultiSet<T>;
  4.        end;
Title: Re: Type "TMyType" is not completly defined
Post by: 440bx on December 08, 2019, 05:24:15 am
Delphi mode
Code: Pascal  [Select][+][-]
  1.   TMultiSet<T> = record
  2.          fField: byte;
  3.          value: ^TMultiSet<T>;
  4.        end;
Thank you for that.  Would you happen to know how the same thing can be done in regular "FPC mode" ?
Title: Re: Type "TMyType" is not completly defined
Post by: avk on December 08, 2019, 06:08:23 am
Code: Pascal  [Select][+][-]
  1.   generic TMultiSet<T> = record
  2.     fField: byte;
  3.     value: ^TMultiset;
  4.   end;  
  5.  
Title: Re: Type "TMyType" is not completly defined
Post by: PascalDragon on December 08, 2019, 11:27:41 am
I tried your example mate, but sadly I get also here a type error:
(attachment!)

And it actually is correct, since he cant know what <T> should mean without  the generic keyword and/or the brackets in PMultiSet<T> i would assume..

but did you see also the attachment above: it says:

"Error: Internal error: 20010001" or the like
The internal error should not be happening, that should probably be considered a bug in FPC but, that is a determination better left to the developers.

An internal error is always considered a bug, because it should not happen.

Code: Pascal  [Select][+][-]
  1.   generic TMultiSet<T> = record
  2.     fField: byte;
  3.     value: ^TMultiset;
  4.   end;  
  5.  

Or more explicit:

Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. {$modeswitch advancedrecords}
  3.  
  4. type
  5.   generic TMultiSet<T> = record
  6.   public type
  7.     PMultiSet = ^specialize TMultiSet<T>;
  8.   public
  9.     fField: Byte;
  10.     value: PMultiSet;
  11.   end;
  12.  
Title: Re: Type "TMyType" is not completly defined
Post by: 440bx on December 08, 2019, 02:02:48 pm

Code: Pascal  [Select][+][-]
  1.   generic TMultiSet<T> = record
  2.     fField: byte;
  3.     value: ^TMultiset;
  4.   end;  
  5.  
Thank you Avk.  That's what I was looking for but for some reason couldn't get there.

Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 10, 2019, 07:43:45 pm
Thanks all for the help, it works fine now!

Sry for the late answer though, I had alot of stuff to do and totally forgot to read..
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 10, 2019, 08:41:26 pm
Btw: What I am still lacking is, may I use still pascals strong type inference, ala: PSet = ^specialize TMultiSet; ?

Since i need a pointer variable of this type within my class  variables and in function parameters!


I  have currently this:

Code: Pascal  [Select][+][-]
  1.  
  2. function  BlockAlloc(const cnt: TMaxCapacity; const shallGrow: Boolean): ^TNode;  //error: Type identifier expected
  3.  

which ofc makes sense but i cant make it work to have a global type definition of this pointer type, either way i get an error when trying to do so, unfortunately, is there any way I can make this work ? would be very appreciated!
Title: Re: Type "TMyType" is not completly defined
Post by: PascalDragon on December 11, 2019, 09:44:47 am
Btw: What I am still lacking is, may I use still pascals strong type inference, ala: PSet = ^specialize TMultiSet; ?

Since i need a pointer variable of this type within my class  variables and in function parameters!


I  have currently this:

Code: Pascal  [Select][+][-]
  1.  
  2. function  BlockAlloc(const cnt: TMaxCapacity; const shallGrow: Boolean): ^TNode;  //error: Type identifier expected
  3.  

which ofc makes sense but i cant make it work to have a global type definition of this pointer type, either way i get an error when trying to do so, unfortunately, is there any way I can make this work ? would be very appreciated!

Using the generic type outside of it's declaration always requires a specialization.

There is a way to solve this:

Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. {$modeswitch advancedrecords}
  3.  
  4. type
  5.   generic TBlockFuncs<T> = record
  6.   public type
  7.     PNode = specialize TNode<T>;
  8.   public
  9.     class function Alloc(const cnt: TMaxCapacity; const shallGrow: Boolean): PNode; static;
  10.   end;
  11.  
  12. // you then call it like this:
  13. type
  14.   TNodeLongInt = specialize TNode<LongInt>;
  15.   TBlockFuncsLongInt = specialize TBlockFuncs<LongInt>;
  16. var
  17.   n: TNodeLongInt;
  18. begin
  19.   n := specialize TBlockFuncs<LongInt>.Alloc(42, false);
  20. end.
  21.  

In theory FPC 3.2 should support the following, but due to a bug it currently does not:

Code: Pascal  [Select][+][-]
  1. generic function BlockAlloc<T>(const cnt: TMaxCapacity; const shallGrow: Boolean): ^specialize TNode<T>;
  2.  
  3. // you'd then call it like this:
  4. var
  5.   n: specialize TNode<LongInt>;
  6. begin
  7.   n := specialize BlockAlloc<LongInt>(42, false);
  8. end.
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 11, 2019, 05:47:56 pm
Hi,

I have to throw out some points here:

* Unfortunately, your solution is not giving me a pointer of TNode<T>, your "PNode" is still
   just a specialized record, not a pointer to it.

* Lets assume, even if this would work, I gotta say, its an actually disgusting syntax, no
   hate at  this point (I love FPC with my heart) but there are some implications which I
   really find deeply unintuitive, for instance: 
       * When I want to create a pointer type of any generic type, I should actually be able,
          like with any pointer type, to get this code running:
         
Code: Pascal  [Select][+][-]
  1. generic PNode<T> = ^specialize TNode<T>
cuz this is IMHO very intuitive, it
          says: "give me the adress of TNode<T> so I need to specifiy the T also within the
          brackets of PNode. This would be atleast one of the logical syntax-assumptions:


* To the general way of generics , why am I not just able to create a:
   
Code: Pascal  [Select][+][-]
  1.       generic TBla<T>= specialize TElement<T>;    
   This or any other variations I tried doesnt work also, like: I have a unit, called Collection, within that unit, I want to   
    create global accessable types from that unit which are accessible publicly, so more concrete:

 
Code: Pascal  [Select][+][-]
  1.     type
  2.       generic TElement<T> = record
  3.         //some fields, no pointer to itself here!
  4.       end;
  5.  
  6.       PNode = ^specialize TNode;  //something along these lines should work but as I mentioned above, I would
  7.                                                  //find it even more clear to saay: generic PNode<T> = ^specialize TNode<T>
  8.  
  9.       generic TNode<T> = record
  10.         Next: PNode;                                       //make a PNode here possible instead of writing ^TNode;
  11.         Previous: PNode;                                 //make a PNode here possible  instead of writing ^TNode;
  12.         Data: array of specialize TElement<T>;    //specialize here is ok!
  13.         class operator =(const this, other: TNode) : Boolean;
  14.         class operator <>(const this, other: TNode) : Boolean;
  15.       end;
  16.  
  17.       generic TSomeDifferentCollection<T> = record
  18.       private
  19.         //make a PNode here possible  instead of writing ^TNode;
  20.         fFirst: PNode;    //<----
  21.       public
  22.          //make a PNode here possible
  23.          function  BlockAlloc(const cnt: TMaxCapacity; const shallGrow: Boolean): PNode;   //<----
  24.       end;
  25.  
  26.  
 
I hope, since generics are still as I looked into it, described as being in an experimental state and I hope there can be some more intuitive syntax, since its just , as it is right now, not the most pascalish-clear syntax, as it could be.

But I still appreciate obviously all the help and general interesst in these argumentations.


Title: Re: Type "TMyType" is not completly defined
Post by: avk on December 12, 2019, 06:33:40 am
Maybe this will solve your problem?
Code: Pascal  [Select][+][-]
  1. type
  2.   generic TElement<T> = record
  3.     //some fields, no pointer to itself here!
  4.   end;
  5.  
  6.   //PNode = ^specialize TNode;  //something along these lines should work but as I mentioned above, I would
  7.                                              //find it even more clear to saay: generic PNode<T> = ^specialize TNode<T>
  8.  
  9.   generic TNode<T> = record
  10.   type
  11.     PNode = ^TNode;
  12.   var
  13.     Next: PNode;                                       //make a PNode here possible instead of writing ^TNode;
  14.     Previous: PNode;                                 //make a PNode here possible  instead of writing ^TNode;
  15.     Data: array of specialize TElement<T>;    //specialize here is ok!
  16.     class operator =(const this, other: TNode) : Boolean;
  17.     class operator <>(const this, other: TNode) : Boolean;
  18.   end;
  19.  
  20.   generic TSomeDifferentCollection<T> = record
  21.   type
  22.     PNode = ^specialize TNode<T>;
  23.     //or PNode = specialize TNode<T>.PNode;
  24.   private
  25.     //make a PNode here possible  instead of writing ^TNode;
  26.     fFirst: PNode;    //<----
  27.   public
  28.      //make a PNode here possible
  29.      function  BlockAlloc(const cnt: TMaxCapacity; const shallGrow: Boolean): PNode;   //<----
  30.   end;
  31.  
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 12, 2019, 07:07:05 am
Hi @avk thx for ur response, but this wont compile unfortunately :/

Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 12, 2019, 07:17:38 am
but I did indeed something else :-) which works

I made from:
Code: Pascal  [Select][+][-]
  1.  type
  2.     PNode = ^specialize TNode<T>;
  3.  
this:

Code: Pascal  [Select][+][-]
  1.   TTempNode = specialize TNode<T>;
  2.   PNode = ^TTempNode;
  3.  

works so far, I get some other errors, but these are not related to that particualr issue, but still, pls make that intuitive  style possible, its much easier to say: "PNode = ^specialize TNode<T>; " instead of wrapping it into that temp solution i made here
Title: Re: Type "TMyType" is not completly defined
Post by: avk on December 12, 2019, 07:30:48 am
Well yes, it depends on the version of the compiler. I am using trunk.
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 12, 2019, 07:44:26 am
1.)
Well yes, it depends on the version of the compiler. I am using trunk.

what u mean with  that?

2.)
  when i make this:
 
Code: Pascal  [Select][+][-]
  1.  
  2.        list: specialize TDoublyLinkedArray<integer>;
  3.       begin      
  4.         list.Create(100, false);  //some test functions
  5.       end;
  6.  

I get: "Fatal: Compilation aborted"?
Title: Re: Type "TMyType" is not completly defined
Post by: Cyrax on December 12, 2019, 09:02:06 am
1.)
Well yes, it depends on the version of the compiler. I am using trunk.

what u mean with  that?

He means that he is using development version of FPC where the new features are added and the bugs are fixed.

2.)
  when i make this:
 
Code: Pascal  [Select][+][-]
  1.  
  2.        list: specialize TDoublyLinkedArray<integer>;
  3.       begin      
  4.         list.Create(100, false);  //some test functions
  5.       end;
  6.  

I get: "Fatal: Compilation aborted"?

You need to declare that specialization as an type. You can't call Create from class instance variable directly, it needs the class type because compiler magic. One way is to create a class function which returns the instance of the class.
Title: Re: Type "TMyType" is not completly defined
Post by: PascalDragon on December 12, 2019, 09:45:11 am
* Unfortunately, your solution is not giving me a pointer of TNode<T>, your "PNode" is still
   just a specialized record, not a pointer to it.
Sorry, should have been as follows:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. {$modeswitch advancedrecords}
  3.  
  4. type
  5.   generic TBlockFuncs<T> = record
  6.   public type
  7.     PNode = ^specialize TNode<T>;
  8.   public
  9.     class function Alloc(const cnt: TMaxCapacity; const shallGrow: Boolean): PNode; static;
  10.   end;
  11.  
  12. // you then call it like this:
  13. type
  14.   TNodeLongInt = specialize TNode<LongInt>;
  15.   PNodeLongInt = ^TNodeLongInt;
  16.   TBlockFuncsLongInt = specialize TBlockFuncs<LongInt>;
  17. var
  18.   n: PNodeLongInt;
  19. begin
  20.   n := specialize TBlockFuncs<LongInt>.Alloc(42, false);
  21. end.
  22.  

       * When I want to create a pointer type of any generic type, I should actually be able,
          like with any pointer type, to get this code running:
         
Code: Pascal  [Select][+][-]
  1. generic PNode<T> = ^specialize TNode<T>
cuz this is IMHO very intuitive, it
          says: "give me the adress of TNode<T> so I need to specifiy the T also within the
          brackets of PNode. This would be atleast one of the logical syntax-assumptions:
Generic pointers are not allowed.

* To the general way of generics , why am I not just able to create a:
   
Code: Pascal  [Select][+][-]
  1.       generic TBla<T>= specialize TElement<T>;    
   This or any other variations I tried doesnt work also, like: I have a unit, called Collection, within that unit, I want to   
    create global accessable types from that unit which are accessible publicly, so more concrete:
Generic aliases are not allowed.

The following works:
Code: Pascal  [Select][+][-]
  1. type
  2.   generic TElement<T> = record
  3.     //some fields, no pointer to itself here!
  4.   end;
  5.  
  6.   //PNode = ^specialize TNode;  //something along these lines should work but as I mentioned above, I would
  7.                                              //find it even more clear to saay: generic PNode<T> = ^specialize TNode<T>
  8.  
  9.   generic TNode<T> = record
  10.   public type
  11.     PNode = ^specialize TNode<T>;
  12.    public
  13.     Next: PNode;                                       //make a PNode here possible instead of writing ^TNode;
  14.     Previous: PNode;                                 //make a PNode here possible  instead of writing ^TNode;
  15.     Data: array of specialize TElement<T>;    //specialize here is ok!
  16.     class operator =(const this, other: TNode) : Boolean;
  17.     class operator <>(const this, other: TNode) : Boolean;
  18.   end;
  19.  
  20.   generic TSomeDifferentCollection<T> = record
  21.   public type
  22.     PNode = ^specialize TNode<T>;
  23.   private
  24.     //make a PNode here possible  instead of writing ^TNode;
  25.     fFirst: PNode;    //<----
  26.   public
  27.      //make a PNode here possible
  28.      function  BlockAlloc(const cnt: TMaxCapacity; const shallGrow: Boolean): PNode;   //<----
  29.   end;
  30.  
 
I hope, since generics are still as I looked into it, described as being in an experimental state and I hope there can be some more intuitive syntax, since its just , as it is right now, not the most pascalish-clear syntax, as it could be.

Where ever you read that generics are experimental that is outdated.

2.)
  when i make this:
 
Code: Pascal  [Select][+][-]
  1.  
  2.        list: specialize TDoublyLinkedArray<integer>;
  3.       begin      
  4.         list.Create(100, false);  //some test functions
  5.       end;
  6.  

I get: "Fatal: Compilation aborted"?

You need to declare that specialization as an type. You can't call Create from class instance variable directly, it needs the class type because compiler magic. One way is to create a class function which returns the instance of the class.
Assuming that Create is not a constructor, then this works in trunk. For a constructor the following would work in trunk as well:
Code: Pascal  [Select][+][-]
  1. var
  2.   list: specialize TDoublyLinkedArray<integer>;
  3. begin      
  4.    list := specialize TDoublyLinkedArray<integer>.Create(100, false);  //some test functions
  5.  end;
  6. [code]
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 12, 2019, 05:57:58 pm
Ok first, thx for the answers, brought me much further!

second:
   * I have to ask, why is it not allowed to have only 1 definition of "PNode = ^specialize TNode<T>" in a global type
      section, like within an "interface"-section? why must I have it written in each record/class -type  section?
      I understand partly, that the "<T>" is needed somehow to say its a pointer of a TNode<T> and the<T>is not
      known otherwise, but cant you guys make it possible, to write only this and still make the compiler understand
      that: <"declare a pointer to a TNode, even without now knowing what "T" is, so whatever the specialization of
      "T" will be, I just want to have a pointer type of that type">

      I hope I could my suggestion/question formulate properly and understandably ^^

   
Title: Re: Type "TMyType" is not completly defined
Post by: 440bx on December 12, 2019, 06:36:47 pm
<snip>
   * I have to ask, why is it not allowed to have only 1 definition of "PNode = ^specialize TNode<T>" in a global type
      section, like within an "interface"-section? why must I have it written in each record/class -type  section?

      I understand partly, that the "<T>" is needed somehow to say its a pointer of a TNode<T> and the<T>is not
      known otherwise, but cant you guys make it possible, to write only this and still make the compiler understand
      that: <"declare a pointer to a TNode, even without now knowing what "T" is, so whatever the specialization of
      "T" will be, I just want to have a pointer type of that type">
If I understood your questions, the problem, which has no "generic" solution is, if you specialize once with T as "byte" and another time with T as "qword", the problem is, what does PNode point to ?... the specialization with T as "byte" or the specialization with T as "qword" ? The pointer type PNode can only point to one type otherwise there is an unresolvable ambiguity.

IOW, allowing what you're asking for would lead to a case where a variable of type PNode may be a pointer to two (2) - in this example - different things, a record where T is byte and a different record where T is qword, which is not possible. 

HTH.
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 12, 2019, 08:04:33 pm
@440bx:

Actually it  shouldnt matter, since you get a pointer to a TNode<T> and not the <T> itself, so nevermind what T is, if record, some class or some base type, you get a 32/64 bit pointer to that whole TNode<T> thing, if I am not mistaken.
Title: Re: Type "TMyType" is not completly defined
Post by: 440bx on December 12, 2019, 08:36:52 pm
Actually it  shouldnt matter, since you get a pointer to a TNode<T> and not the <T> itself, so nevermind what T is, if record, some class or some base type, you get a 32/64 bit pointer to that whole TNode<T> thing, if I am not mistaken.
It should and does matter, consider this example (which at one time I mistakenly thought should work)
Code: Pascal  [Select][+][-]
  1. type
  2.   PMultiSet = ^TMultiSet;
  3.   generic TMultiSet<T> = record
  4.     next : PMultiSet;
  5.     data : T;
  6.   end;
  7.  
  8. < some stuff here >
  9.  
  10. var
  11.   p : PMultiSet;
  12.  
when MultiSet is specialized using T as byte then var p is a pointer to a MultiSet with data defined as "data : byte;", a subsequent specialization using T as qword causes p to point to a MultiSet with data defined as "data : qword;".  After that, var p  points to two different types simultaneously which is not possible.
Title: Re: Type "TMyType" is not completly defined
Post by: PascalDragon on December 13, 2019, 09:44:37 am
Ok first, thx for the answers, brought me much further!

second:
   * I have to ask, why is it not allowed to have only 1 definition of "PNode = ^specialize TNode<T>" in a global type
      section, like within an "interface"-section? why must I have it written in each record/class -type  section?
      I understand partly, that the "<T>" is needed somehow to say its a pointer of a TNode<T> and the<T>is not
      known otherwise, but cant you guys make it possible, to write only this and still make the compiler understand
      that: <"declare a pointer to a TNode, even without now knowing what "T" is, so whatever the specialization of
      "T" will be, I just want to have a pointer type of that type">

      I hope I could my suggestion/question formulate properly and understandably ^^

   
It is not possible to have a general PNode as the compiler needs to know the size of the right side so that Inc or array access work correctly.

What would technically be possible would be what you had suggested earlier with generic PNode<T> = ^specialize TNode<T>, but it would not safe anything:
Code: Pascal  [Select][+][-]
  1. type
  2.   generic TNode<T> = record
  3.   end;
  4.  
  5.   generic PNode<T> = ^specialize TNode<T>;
  6.  
  7.   generic TSomething<T> = record
  8.     function CreateNode: specialize PNode<T>;
  9.   end;
You see the declaration of CreateNode? To avoid having to type that out I'd have to do this anyway:
Code: Pascal  [Select][+][-]
  1.   generic TSomething<T> = record
  2.   public type
  3.     MyPNode = specialize PNode<T>;
  4.   public
  5.     function CreateNode: MyPNode;
  6.   end;

So there is no real difference between the existing solution and your proposed on except one single ^.

Also records can only be forward declared for the use in pointers (which would be the case here), but for generics that provides a whole new box of potential problems. (There is a bug report to allow forward declarations of generic classes for Delphi compatibility, but that needs to be handled with care as well)
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 13, 2019, 01:53:35 pm
OK I see the issue :D

But nice to get a better understanding of how generics work in FPC!


Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 13, 2019, 02:03:11 pm
ah and also:

why does this code still produces a: "compilation aborted" error?


Code: Pascal  [Select][+][-]
  1.   procedure DoStuff;
  2.      type
  3.        TTestArray = specialize TDoublyLinkedArray<byte>;
  4.       var
  5.         list: TTestArray;
  6.    begin
  7.       list := TTestArray.Create(0, false);
  8.    end;  
  9.  

Sidenotes:
- windows 10 pro
- CPU=x64
- FPC 3.0.4 (current stable version) 64bit compiler
- lazarus IDE: 2.0.6
Title: Re: Type "TMyType" is not completly defined
Post by: PascalDragon on December 14, 2019, 10:50:31 am
Would you please provide a simple, complete, compilable example (e.g. I don't know what TDoublyLinkedArray is declared as) as well as the full output you receive? (If you use Lazarus you need to right click in the message window where there is a menu item to copy all messages)
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 14, 2019, 04:56:30 pm
Hi, @PascalDragon

I have DM you an attachment, it says: the abortion of the compilation process has to do something with the an AccessViolation, but it only occurs when I make use of:

Code: Pascal  [Select][+][-]
  1.  
  2. type
  3.   TList = specialize TDoublyLinkedArray<byte>;   //or the same shit happens when i do:
  4.  
  5. var
  6.    list1: specialize TDoublyLinkedArray<byte>      {just without the TList in this case but also with, see:}
  7.    list2: TList;  // same error
  8.  
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 14, 2019, 05:00:05 pm
see the testcase.zip for this issue, all files needed are there!
Title: Re: Type "TMyType" is not completly defined
Post by: avk on December 14, 2019, 07:28:54 pm
What happens if you replace in your code
Code: Pascal  [Select][+][-]
  1.       generic TElement<T> = record
  2.         DeletedAt, SwapedAt: TIndex;
  3.         Origin: record
  4.           Value: T;
  5.           Index: TIndex;
  6.         end;
  7.  
  8.         //class operator = (const this, other: TElement) : Boolean;
  9.         //class operator <>(const this, other: TElement) : Boolean;
  10.  
  11.         case isArraySorted: boolean of
  12.           True:  (InsertedBetween: array[0..1] of TIndex;);
  13.           False: (InsertedAt: TIndex);
  14.       end;  
  15.  
with
Code: Pascal  [Select][+][-]
  1.   generic TElement<T> = record
  2.   type
  3.     TOrigin = record
  4.       Value: T;
  5.       Index: TIndex;
  6.     end;
  7.   var
  8.     DeletedAt, SwapedAt: TIndex;
  9.     Origin: TOrigin;
  10.     case isArraySorted: boolean of
  11.       True:  (InsertedBetween: array[0..1] of TIndex;);
  12.       False: (InsertedAt: TIndex);
  13.   end;  
  14.  
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 14, 2019, 08:00:04 pm
What happens if you replace in your code
Code: Pascal  [Select][+][-]
  1.       generic TElement<T> = record
  2.         DeletedAt, SwapedAt: TIndex;
  3.         Origin: record
  4.           Value: T;
  5.           Index: TIndex;
  6.         end;
  7.  
  8.         //class operator = (const this, other: TElement) : Boolean;
  9.         //class operator <>(const this, other: TElement) : Boolean;
  10.  
  11.         case isArraySorted: boolean of
  12.           True:  (InsertedBetween: array[0..1] of TIndex;);
  13.           False: (InsertedAt: TIndex);
  14.       end;  
  15.  
with
Code: Pascal  [Select][+][-]
  1.   generic TElement<T> = record
  2.   type
  3.     TOrigin = record
  4.       Value: T;
  5.       Index: TIndex;
  6.     end;
  7.   var
  8.     DeletedAt, SwapedAt: TIndex;
  9.     Origin: TOrigin;
  10.     case isArraySorted: boolean of
  11.       True:  (InsertedBetween: array[0..1] of TIndex;);
  12.       False: (InsertedAt: TIndex);
  13.   end;  
  14.  
Good news:
  It compiles fine! (but why does the problem seemingly rely on the origin:record... stuff, it should also have
  worked as such, shouldnt it?

Bad news: 
  It compiles, however: when i want to edit the "create" function of the TDoublyLinkedArraay<T> who again makes use of the TNode<T> who again makes use of ur edited TElement<T> record, I cant press [CTRL] + MouseClick like jumping through the editor to reach another line of code, because it tells me for some reason:

"Case only allowed in record"?

I am confused :D
 
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 14, 2019, 08:05:19 pm
look attachment:

(When i want to press [Ctrl] + ENTER to get syntax-completion it jumps to the red line in the image attached and says: "Case only allowed in records"

I have btw a concern, even when this works, like:

Am i able to assign a value of PNode which comes from TNode<T> type-section to a PNode-variabletype which comes from TDoublyLinkedArray<T> type-section, hence my issue, that i wanted a globally PNode, since i am afraid that it doesnt assign, since it sees both of these as different types, technically, even tho, they are symantically same.
Title: Re: Type "TMyType" is not completly defined
Post by: avk on December 14, 2019, 08:31:28 pm
This seems to be a Codetools bug.
However, there is also a compiler bug. Let's wait for what @PascalDragon will say.
Title: Re: Type "TMyType" is not completly defined
Post by: Shpend on December 14, 2019, 08:58:08 pm
This seems to be a Codetools bug.
However, there is also a compiler bug. Let's wait for what @PascalDragon will say.

To the first, yes it must be, since when i dont use the syntax completion, I can still compile the code and it runs perfectly fine.

And to my early "issue" that the assignment from different PNodes to eachother is gone too, since they are assignable to eachother which makes sense, great so far.

Now, where do yozu assume a compiler bug, as I said, the error is gone, because it had not something to do with the specialize TDoublyLinkedArray<T> codeline, or am I wrong?
Title: Re: Type "TMyType" is not completly defined
Post by: avk on December 15, 2019, 06:45:04 am
Yes, you see that the compiler finds the problem in TElement and at first glance it is not clear why it successfully compiles the second variant but crashes on the first.
And I suppose "Compilation raised exception internally" always means a compiler bug.
Title: Re: Type "TMyType" is not completly defined
Post by: PascalDragon on December 15, 2019, 06:34:36 pm
It seems that anonymous records are not yet handled correctly inside generics. Please report it as a bug so that it isn't forgotten, but only include the source files and try to get rid of the Globals.pas (just copy the required types to the doublyLinkedArray.pas).
Title: Re: Type "TMyType" is not completly defined
Post by: avk on December 16, 2019, 07:02:33 am
Done, 0036446 (https://bugs.freepascal.org/view.php?id=36446)
Title: Re: Type "TMyType" is not completly defined
Post by: PascalDragon on December 16, 2019, 09:09:32 am
Thanks.
TinyPortal © 2005-2018