Recent

Author Topic: Type "TMyType" is not completly defined  (Read 7262 times)

Shpend

  • Full Member
  • ***
  • Posts: 167
Re: Type "TMyType" is not completly defined
« Reply #15 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..

Shpend

  • Full Member
  • ***
  • Posts: 167
Re: Type "TMyType" is not completly defined
« Reply #16 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!
« Last Edit: December 10, 2019, 08:56:02 pm by Shpend »

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Type "TMyType" is not completly defined
« Reply #17 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.

Shpend

  • Full Member
  • ***
  • Posts: 167
Re: Type "TMyType" is not completly defined
« Reply #18 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.


« Last Edit: December 11, 2019, 06:06:16 pm by Shpend »

avk

  • Hero Member
  • *****
  • Posts: 752
Re: Type "TMyType" is not completly defined
« Reply #19 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.  

Shpend

  • Full Member
  • ***
  • Posts: 167
Re: Type "TMyType" is not completly defined
« Reply #20 on: December 12, 2019, 07:07:05 am »
Hi @avk thx for ur response, but this wont compile unfortunately :/


Shpend

  • Full Member
  • ***
  • Posts: 167
Re: Type "TMyType" is not completly defined
« Reply #21 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

avk

  • Hero Member
  • *****
  • Posts: 752
Re: Type "TMyType" is not completly defined
« Reply #22 on: December 12, 2019, 07:30:48 am »
Well yes, it depends on the version of the compiler. I am using trunk.

Shpend

  • Full Member
  • ***
  • Posts: 167
Re: Type "TMyType" is not completly defined
« Reply #23 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"?

Cyrax

  • Hero Member
  • *****
  • Posts: 836
Re: Type "TMyType" is not completly defined
« Reply #24 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.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Type "TMyType" is not completly defined
« Reply #25 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]

Shpend

  • Full Member
  • ***
  • Posts: 167
Re: Type "TMyType" is not completly defined
« Reply #26 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 ^^

   

440bx

  • Hero Member
  • *****
  • Posts: 3944
Re: Type "TMyType" is not completly defined
« Reply #27 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.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Shpend

  • Full Member
  • ***
  • Posts: 167
Re: Type "TMyType" is not completly defined
« Reply #28 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.

440bx

  • Hero Member
  • *****
  • Posts: 3944
Re: Type "TMyType" is not completly defined
« Reply #29 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.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018