Recent

Author Topic: Proposal: unions as a new type and arrays with number of elements  (Read 25060 times)

korba812

  • Sr. Member
  • ****
  • Posts: 483
Re: New structure data type — union
« Reply #15 on: April 28, 2023, 01:18:34 pm »
A generic union is not possible (I don't think so anyway).
example

type
union<P,Q>=record
case integer of
0:(A:P);
1:(B:Q);
end;

Why do you think so? You can create a generic record with variable structure:
Code: Pascal  [Select][+][-]
  1. type
  2.   generic TUnion<P,Q> = record
  3.     case integer of
  4.     0:(A:P);
  5.     1:(B:Q);
  6.   end;
  7.  
  8.   TSpecUnion = specialize TUnion<Integer, DWord>;
  9.  

flowCRANE

  • Hero Member
  • *****
  • Posts: 937
Re: New structure data type — union
« Reply #16 on: April 28, 2023, 01:49:02 pm »
Guys, this thread isn't about generic structures, it's about unions, so please don't go off-topic.
Lazarus 4.2 with FPC 3.2.2, Windows 11 — all 64-bit

Working solo on a top-down retro-style action/adventure game (pixel art), programming the engine from scratch, using Free Pascal and SDL3.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12195
  • Debugger - SynEdit - and more
    • wiki
Re: New structure data type — union
« Reply #17 on: April 28, 2023, 02:47:46 pm »

The same as in the case of records. All fields of such a union occupy the same memory area. For example:

Code: Pascal  [Select][+][-]
  1. type
  2.   TFoo = union
  3.     Letter: Char;  // TFoo.Letter
  4.     Code:   UInt8; // TFoo.Code
  5.   end;
Well up to this point it is indeed just syntax.

This can be written in pascal:
Code: Pascal  [Select][+][-]
  1.   TFoo = record
  2.     case integer of
  3.     1: ( Letter: Char );
  4.     2: ( Code:   UInt8 );
  5.   end;

Yes, it is more verbose. Yes, it is more chars to type.
But it is just a change in Syntax. And it could be easily translated using some sort of script.

As for, what is easier to use/read/write/maintan/... Or even "makes more sense" => well that is to a certain degree subjective.



As for
but also allows fields to be declared as unions, and subsequent fields (including structures and unions) below them.

There I would say it is nor so much about syntax. It currently needs a nested record, but then you have a field name for it, and identifiers must be prefixed.

So allowing something like
Code: Pascal  [Select][+][-]
  1.   TFoo = record
  2.     begin case integer of
  3.     1: ( Letter: Char );
  4.     2: ( Code:   UInt8 );
  5.     end;
  6.   CommonField: TBar; // not in the case block
  7. end;
is imho a feature.







flowCRANE

  • Hero Member
  • *****
  • Posts: 937
Re: New structure data type — union
« Reply #18 on: April 28, 2023, 03:00:20 pm »
So allowing something like
Code: Pascal  [Select][+][-]
  1.   TFoo = record
  2.     begin case integer of
  3.     1: ( Letter: Char );
  4.     2: ( Code:   UInt8 );
  5.     end;
  6.   CommonField: TBar; // not in the case block
  7. end;
is imho a feature.

I proposed shortening the syntax, and you added more words, which would make the union body even more complicated. 8)

Come on guys, it doesn't make any sense. See how these proposals compare:

Code: Pascal  [Select][+][-]
  1. type                               type
  2.   TFoo = record                      TFoo = record
  3.     begin case integer of              union
  4.       1: ( Letter: Char );   {vs}        Letter: Char;
  5.       2: ( Code:   UInt8 );              Code:   UInt8;
  6.     end;                               end;
  7.     CommonField: TBar;                 CommonField: TBar;
  8.   end;                               end;
  9.  
« Last Edit: April 28, 2023, 03:04:52 pm by furious programming »
Lazarus 4.2 with FPC 3.2.2, Windows 11 — all 64-bit

Working solo on a top-down retro-style action/adventure game (pixel art), programming the engine from scratch, using Free Pascal and SDL3.

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: New structure data type — union
« Reply #19 on: April 28, 2023, 05:29:22 pm »
A generic union is not possible (I don't think so anyway).
example

type
union<P,Q>=record
case integer of
0:(A:P);
1:(B:Q);
end;

Why do you think so? You can create a generic record with variable structure:
Code: Pascal  [Select][+][-]
  1. type
  2.   generic TUnion<P,Q> = record
  3.     case integer of
  4.     0:(A:P);
  5.     1:(B:Q);
  6.   end;
  7.  
  8.   TSpecUnion = specialize TUnion<Integer, DWord>;
  9.  
Hi korba812.
If I try that method I get:
 Error: Type parameters may require initialization/finalization - cannot be used in variant records
 Error: Type parameters may require initialization/finalization - cannot be used in var

I can use union as an object + method.
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. {$APPTYPE CONSOLE}
  3.  
  4. type
  5. generic union<A,B>=object
  6. answer:B;
  7.  procedure unite(z:A);
  8. end;
  9.  
  10. procedure union.unite(z:A);
  11. var
  12.  y:B absolute z;
  13. begin
  14. answer:=y;
  15. end;
  16.  
  17.  
  18.  
  19.  
  20. function rgb(r:byte;g:byte;b:byte) :uint32;
  21.    begin
  22.    exit(((b Shl 16) Or ((g) Shl 8) Or (r) Or $FF000000)- $FF000000)
  23. end;
  24.  
  25. type aob=array[1..3] of byte;
  26.  
  27. var
  28. col:uint32;
  29. a:aob;
  30. z:specialize union<uint32,aob>;
  31. z2:specialize union<aob,uint32>;
  32.  
  33.  
  34. begin
  35. col:=rgb(100,150,250);
  36. writeln('colour uint32 = ',col);
  37. z.unite(col);
  38. writeln('= rgb ',z.answer[1],',',z.answer[2],',',z.answer[3]);
  39.  
  40. a[1]:=100;a[2]:=150;a[3]:=250;
  41. z2.unite(a);
  42. writeln(' = ',z2.answer);
  43. writeln;
  44. writeln('Press enter to exit . . .');
  45. readln;
  46. end.
  47.  
  48.  
  49.  
  50.  

Curt Carpenter

  • Hero Member
  • *****
  • Posts: 729
Re: New structure data type — union
« Reply #20 on: April 28, 2023, 06:32:16 pm »
There's a difference, I think, in appreciation for old-school Pascal syntax between "furious program maintainer two years later" and "furious programmer."   

As a trivial example, I read "Unsigned: array[4] of UInt8;" and immediately wonder where the range of the index for this array is going to be revealed.  That's probably an artifact of old age though, not technical merit one way or another.

korba812

  • Sr. Member
  • ****
  • Posts: 483
Re: New structure data type — union
« Reply #21 on: April 28, 2023, 06:41:07 pm »
Hi korba812.
If I try that method I get:
 Error: Type parameters may require initialization/finalization - cannot be used in variant records
 Error: Type parameters may require initialization/finalization - cannot be used in var
I don't have this problem but I use FPC trunk. It's probably been fixed/improved in the meantime. Of course you can't use types that require initialization/finalization in the variable part of record (string, dynamic array...).

flowCRANE

  • Hero Member
  • *****
  • Posts: 937
Re: New structure data type — union
« Reply #22 on: April 28, 2023, 06:59:09 pm »
There's a difference, I think, in appreciation for old-school Pascal syntax between "furious program maintainer two years later" and "furious programmer."

I don't understand what exactly you mean.

Quote
As a trivial example, I read "Unsigned: array[4] of UInt8;" and immediately wonder where the range of the index for this array is going to be revealed.

As a trivial example, look at this:

Code: Pascal  [Select][+][-]
  1. Foo: array [UInt8] of Char; // array of "256" chars, indexed from "0" to "255"

This construction also does not contain a range, but a number of elements. The compiler is able to determine the indexation automatically (yes, this notation is correct and supported by FPC and Delphi). It must check the data type used and the range of values available for it, which can be converted to the number of elements.

In the case of specifying the number of elements as a positive (or non-negative) numeric literal, the compiler doesn't need to check anything, there is no extra work, and yet this syntax is not supported. Shame. In most cases, the indexation is the default (0 to n-1), so the number of items should be promoted, as in other languages, rather than a range of indexes. Of course, both forms should be supported.
Lazarus 4.2 with FPC 3.2.2, Windows 11 — all 64-bit

Working solo on a top-down retro-style action/adventure game (pixel art), programming the engine from scratch, using Free Pascal and SDL3.

mas steindorff

  • Hero Member
  • *****
  • Posts: 565
Re: New structure data type — union
« Reply #23 on: April 28, 2023, 07:54:22 pm »
I work a lot with unions in both C and pascal.  At first I too thought the c version of the union was better but have come to change my mind after several years. 
I transfer lots of different data types (and lengths) over a stream and the best way to handle these is to create packed records of each posable packet and overlay them all onto a block of bytes.  where the case number comes handy is for documentation. a byte in the header selects which packet format to use. I use this selection code as the case index so I have
...
 0:(header:Tbaseheader);  // only the header that all records include
...
 105:(Tref : tTimeRefRec);    // when the header code is 105, use this union
...

 I also try to keep the C code and the external documentation up to date but the pascal code has become my go to to find an unused select code or to look up an existing one even when I have the C code in front of me. (and I do document everything as the projects I create last decades)   
MAS
 
windows 10 &11, Ubuntu 21+ IDE 3.4 general releases

Curt Carpenter

  • Hero Member
  • *****
  • Posts: 729
Re: New structure data type — union
« Reply #24 on: April 28, 2023, 11:24:51 pm »
There's a difference, I think, in appreciation for old-school Pascal syntax between "furious program maintainer two years later" and "furious programmer."

I don't understand what exactly you mean.

Sorry, I meant that there are important differences between programming furiously to get something to work (my normal mode) and programming done with an eye toward helping the person a few years down the road that may be tasked with modifying or repairing an existing program.  The latter argues for prioritizing clarity even in trivial things. 

For example: the difference between
Code: Pascal  [Select][+][-]
  1. foo: array[uint8] of char;
and
Code: Pascal  [Select][+][-]
  1. foo: array[0..255] of char;
is exactly one keystroke, but  that one keystroke immediately informs some future reader of the index range and size of the array.  Might not help, but certainly can't hurt.  And of course
Code: Pascal  [Select][+][-]
  1. Unsigned: array[4] of UInt8;
doesn't compile at all in the current language (although one might argue that it should if we simply adopt the convention that all arrays are indexed from 0 unless otherwise specified).

 

flowCRANE

  • Hero Member
  • *****
  • Posts: 937
Re: New structure data type — union
« Reply #25 on: April 28, 2023, 11:41:39 pm »
a byte in the header selects which packet format to use. I use this selection code as the case index so I have
...
 0:(header:Tbaseheader);  // only the header that all records include
...
 105:(Tref : tTimeRefRec);    // when the header code is 105, use this union
...

And how do you use these numbers in practice, like the values "0" or "105" above?

In my current project, for example, I have a union to store data about the text tokens. There are five types of tokens, each of them uses different data. The token is declared as variant record, and to be able to distinguish the type of the token (and use the apropriate record fields), the first field in the structure is the field with the numeric token type:

Code: Pascal  [Select][+][-]
  1. type
  2.   TGame_TextToken = record
  3.     Type_: TGame_UInt8;
  4.     case TGame_UInt8 of
  5.       GAME_TEXT_TOKEN_WORD: ( Word: record
  6.         Word: PGame_Char;
  7.         Rect: TGame_RectS32;
  8.       end );
  9.       GAME_TEXT_TOKEN_WHITE: ( White: record
  10.         NumChars: TGame_SInt32;
  11.         W:        TGame_SInt32;
  12.         H:        TGame_SInt32;
  13.       end );
  14.       GAME_TEXT_TOKEN_COLOR: ( Color: record
  15.         R: TGame_UInt8;
  16.         G: TGame_UInt8;
  17.         B: TGame_UInt8;
  18.       end );
  19.       GAME_TEXT_TOKEN_ALPHA: ( Alpha: record
  20.         Level: TGame_UInt8;
  21.       end );
  22.       GAME_TEXT_TOKEN_FONT: ( Font: record
  23.         Index: TGame_UInt8;
  24.       end );
  25.   end;
  26.  

If I need to distinguish the type of token, I check the value of the Type_ field, in a conditional statement or a selection statement. In my opinion, this field must exist, because I need to distinguish the token type in some way. The line case TGame_UInt8 of is useless to me. What does it give me? Nothing but disappointment that it has to exist in code.

My proposal is to add a new data type and extend the syntax so that unions can be conveniently and legibly declared (variant-records are to be left intact). Below is a comparison of the record with the proposed union:

Code: Pascal  [Select][+][-]
  1. type                                            type
  2.   TGame_TextToken = record                        TGame_TextToken = record
  3.     Type_: TGame_UInt8;                             Type_: TGame_UInt8;
  4.     case TGame_UInt8 of                             union
  5.       GAME_TEXT_TOKEN_WORD: ( Word: record            Word: record
  6.         Word: PGame_Char;                               Word: PGame_Char;
  7.         Rect: TGame_RectS32;                            Rect: TGame_RectS32;
  8.       end );                                          end;
  9.       GAME_TEXT_TOKEN_WHITE: ( White: record          White: record
  10.         NumChars: TGame_SInt32;                         NumChars: TGame_SInt32;
  11.         W:        TGame_SInt32;                         W:        TGame_SInt32;
  12.         H:        TGame_SInt32;               {vs}      H:        TGame_SInt32;
  13.       end );                                          end;
  14.       GAME_TEXT_TOKEN_COLOR: ( Color: record          Color: record
  15.         R: TGame_UInt8;                                 R: TGame_UInt8;
  16.         G: TGame_UInt8;                                 G: TGame_UInt8;
  17.         B: TGame_UInt8;                                 B: TGame_UInt8;
  18.       end );                                          end;
  19.       GAME_TEXT_TOKEN_ALPHA: ( Alpha: record          Alpha: record
  20.         Level: TGame_UInt8;                             Level: TGame_UInt8;
  21.       end );                                          end;
  22.       GAME_TEXT_TOKEN_FONT: ( Font: record            Font: record
  23.         Index: TGame_UInt8;                             Index: TGame_UInt8;
  24.       end );                                          end;
  25.   end;                                              end;
  26.                                                   end;
  27.  

Variant-records look like syntactical bloatware, while the record with the union proposed is short, clean and very readable.
« Last Edit: April 29, 2023, 12:42:41 am by furious programming »
Lazarus 4.2 with FPC 3.2.2, Windows 11 — all 64-bit

Working solo on a top-down retro-style action/adventure game (pixel art), programming the engine from scratch, using Free Pascal and SDL3.

flowCRANE

  • Hero Member
  • *****
  • Posts: 937
Re: New structure data type — union
« Reply #26 on: April 28, 2023, 11:56:07 pm »
Sorry, I meant that there are important differences between programming furiously to get something to work (my normal mode) and programming done with an eye toward helping the person a few years down the road that may be tasked with modifying or repairing an existing program.  The latter argues for prioritizing clarity even in trivial things.

I do not quite understand what this has to do with the proposal to add a new data type.

Quote
For example: the difference between
Code: Pascal  [Select][+][-]
  1. foo: array[uint8] of char;
and
Code: Pascal  [Select][+][-]
  1. foo: array[0..255] of char;
is exactly one keystroke, but  that one keystroke immediately informs some future reader of the index range and size of the array.

It's not about the number of characters to type, it's about being able to specify the number of elements, not range of indexes. In most cases, arrays contain a fixed number of elements, and the indexing is just the default, as it should be for programmers — that is, from "0".

Quote
Might not help, but certainly can't hurt.

Remember that in all other programming languages, you don't specify indices, but rather the number of elements. All programmers in the world know that it indexes from "0", no need to explain it to anyone. And we — Pascal programmers — are a miserable fraction of the number of programmers, we are practically irrelevant, because who uses Pascal today?

Quote
And of course
Code: Pascal  [Select][+][-]
  1. Unsigned: array[4] of UInt8;
doesn't compile at all in the current language [...]

I know that such a syntax is not compilable — that's why I proposed it as a feature to implement.

Quote
(although one might argue that it should if we simply adopt the convention that all arrays are indexed from 0 unless otherwise specified).

All arrays in ~all significant programming languages are indexed from "0". All dynamic arrays in Pascal are indexed from "0". Zero-based indexing is as common as air.
« Last Edit: April 29, 2023, 12:03:24 am by furious programming »
Lazarus 4.2 with FPC 3.2.2, Windows 11 — all 64-bit

Working solo on a top-down retro-style action/adventure game (pixel art), programming the engine from scratch, using Free Pascal and SDL3.

Curt Carpenter

  • Hero Member
  • *****
  • Posts: 729
Re: New structure data type — union
« Reply #27 on: April 29, 2023, 12:20:13 am »
OK. 

flowCRANE

  • Hero Member
  • *****
  • Posts: 937
Re: New structure data type — union
« Reply #28 on: April 29, 2023, 12:58:50 am »
There's one more thing I'm curious about, and unfortunately I'm having trouble finding an explanation on Google. Earlier, I gave an example union as an illustration of my proposal:

Code: Pascal  [Select][+][-]
  1. type
  2.   TFoo = record
  3.     Chunks: union
  4.       Number: UInt32;
  5.       Words:  array[2] of UInt16;
  6.       Bytes:  union
  7.         Unsigned: array[4] of UInt8;
  8.         Signed:   array[4] of Int8;
  9.       end;
  10.     end;
  11.     Other: UInt32;
  12.   end;
  13.  

@korba812 translated this code to the currently supported variant-record:

Code: Pascal  [Select][+][-]
  1. type
  2.   TFoo = record
  3.     Chunks: record
  4.       case Byte of
  5.       0: (Number: UInt32);
  6.       1: (Words:  array [0 .. 1] of UInt16);
  7.       2: (Bytes:  record
  8.         case Boolean of
  9.           True: (Unsigned: array [0 .. 3] of UInt8);
  10.           False: (Signed:   array [0 .. 3] of Int8);
  11.         end;);
  12.       end;
  13.     Other: UInt32;
  14.   end;
  15.  

I have a questions. Why is the Byte type used in the first case of and Boolean in the second? How can I actually use these types? Can someone give an example and write something more about it, please?
Lazarus 4.2 with FPC 3.2.2, Windows 11 — all 64-bit

Working solo on a top-down retro-style action/adventure game (pixel art), programming the engine from scratch, using Free Pascal and SDL3.

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: New structure data type — union
« Reply #29 on: April 29, 2023, 01:03:50 am »
I have a questions. Why is the Byte type used in the first case of and Boolean in the second? How can I actually use these types? Can someone give an example and write something more about it, please?
Byte (256 states) is used in the first place because 3 does not fit into a boolean (2 states). He could just as well have used a word or longword but that is a bit overkill. For the second case he could just as well used a byte but again overkill for selecting between 2 different states. You are free to choose though.

You are free to choose any (simple) type there (byte, char, integer, etc).

btw: your suggestion proposal for "Unsigned: array[4] of UInt8;" is a good one. There are pascal dialects that implemented it that way which is very convenient instead of having to write "Unsigned: array[0..4-1] of UInt8;"
« Last Edit: April 29, 2023, 01:21:25 am by TRon »
Today is tomorrow's yesterday.

 

TinyPortal © 2005-2018