Recent

Author Topic: Variant Record Behavior  (Read 842 times)

simone

  • Hero Member
  • *****
  • Posts: 626
Variant Record Behavior
« on: November 01, 2024, 12:04:33 pm »
I confess, I have not used variant records very often during the nearly 35 years that I have been programming in (Object) Pascal. For this reason, probably, I had missed a subtle behavior, which I illustrate with the following example.

Code: Pascal  [Select][+][-]
  1. program project1;
  2. type
  3.   TSide=integer;
  4.  
  5.   TPinCase=(psRectangle, psEllipse, psPolygon);
  6.  
  7.   TBorderPoint=record
  8.     case TPinCase of
  9.       psRectangle : (Side : TSide);
  10.       psEllipse   : (Angle : integer);
  11.       psPolygon   : (Segment : integer; Position : integer);
  12.   end;
  13.  
  14. var
  15.   P : TBorderPoint;
  16.  
  17. begin
  18.   P.Side:=1;
  19.   P.Angle:=300;
  20.   writeln(P.Side); // print 300, not 1
  21.   readln;
  22. end.

Side and Angle are fields belonging to two different cases. If I first assign Side, then Angle, the latter value overwrites Side. For this reason, the example shows 300, not 1. From a technical point of view, I understand the reasons for this behavior. In the variant records the fields of the different cases share the same memory layout. Basically they are like unions in C.

Since this it seems to me that this behavior is not documented, I ask you if this is actually the expected behavior or an implementation dependent behavior.

Thanks for the usual support.

« Last Edit: November 01, 2024, 12:07:21 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

440bx

  • Hero Member
  • *****
  • Posts: 4727
Re: Variant Record Behavior
« Reply #1 on: November 01, 2024, 12:21:27 pm »
It is the expected behavior.

Pascal variant part in a record is C's union.  They share the memory and that is documented.

HTH.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 16139
  • Censorship about opinions does not belong here.
Re: Variant Record Behavior
« Reply #2 on: November 01, 2024, 12:21:41 pm »
It IS basically like a union in C. Always has been, although there are subtle differences, it uses indeed the same memory layout.
Documentation: https://www.freepascal.org/docs-html/ref/refsu15.html
« Last Edit: November 01, 2024, 12:28:14 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

440bx

  • Hero Member
  • *****
  • Posts: 4727
Re: Variant Record Behavior
« Reply #3 on: November 01, 2024, 12:30:57 pm »
I was looking for the documentation regarding the memory allocation applicable to the variant part of a record and could not find it.

I looked online (Wiki) and in the Language Reference Guide and did not find anywhere an explanation regarding the variant part's memory usage.

It's definitely documented in standard Pascal.


(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

simone

  • Hero Member
  • *****
  • Posts: 626
Re: Variant Record Behavior
« Reply #4 on: November 01, 2024, 12:38:49 pm »
@440bx @Thaddy, Thanks for confirming my interpretation.

Variant records exist since the beginning of Pascal, already described in PASCAL - User Manual and Report by Jensen & Wirth (page 44 in the second edition I own). But I have not found, to my memory, the specification of this behavior in the literature. Where can I find it?

Edit:
I don't seem to me that such a specification is in ISO 7185 and ISO 10206 documents
« Last Edit: November 01, 2024, 01:20:57 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

440bx

  • Hero Member
  • *****
  • Posts: 4727
Re: Variant Record Behavior
« Reply #5 on: November 01, 2024, 02:01:52 pm »
The original Pascal standard (J&W), 6.2.2, page 148, states:
Quote
A  record  type  may have  several  variants,  in  which  case  a  certain
field  may  be  designated  as  the  tag field,  whose  value  indicates
which  variant  is  assumed  by  the  record  variable  at  a  given  time.

That passage implies that only 1 variant at a time can be active.  This in turn implies they share memory.

I could not find anything that even implied it in the more recent Pascal standards.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

simone

  • Hero Member
  • *****
  • Posts: 626
Re: Variant Record Behavior
« Reply #6 on: November 01, 2024, 04:45:57 pm »
You are right. It is in the report part of the book you cited, but not in the user manual part that I had seen.

However I believe this behavior should be explicitly described in the current official documentation.

Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

Warfley

  • Hero Member
  • *****
  • Posts: 1734
Re: Variant Record Behavior
« Reply #7 on: November 01, 2024, 08:14:32 pm »
That passage implies that only 1 variant at a time can be active.  This in turn implies they share memory.
Not necessarily. Take the following code:
Code: Pascal  [Select][+][-]
  1. generic TMyUnion<T, U> = record
  2.   Selected:Boolean;
  3.   first: T;
  4.   Second: U;
  5.  
  6.   procedure setSelected(AValue: Boolean);
  7. end;
  8.  
  9. procedure TMyUnion.setSelected(AValue: Boolean);
  10. begin
  11.   if selected=AValue then Exit;
  12.   if selected then
  13.   begin
  14.     Finalize(first);
  15.     Initialize(second);
  16.   end
  17.   else
  18.   begin
  19.     Finalize(Second);
  20.     Initialize(first);
  21.   end;
  22.   Selected:=AValue;
  23. end;

Now first and second do not share memory, but only ever one will be initialized (and thereby valid to be accessed) while the otherone will not.

Of course such an implementation does not make that much sense, because it's the exact same as if they'd be sharing memory, so basically it's just less efficient, but still it's possible to implement that way..

Also as the comparison to C unions was drawn, I feel the need to point out that the C standard says about unions:
Quote
When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.
So while the overlapping memory allowing to read out the value in different bit reperesentation, this is unspecified behavior and implementation dependent.
It is not a feature of C itself but rather of GCC/Clang/whatever C compiler you use.
(Note that it says "unspecified" and not "undefined", which means it is implementation dependent, while "undefined" would mean it's never correct to read it out)

440bx

  • Hero Member
  • *****
  • Posts: 4727
Re: Variant Record Behavior
« Reply #8 on: November 01, 2024, 10:33:52 pm »
However I believe this behavior should be explicitly described in the current official documentation.
I agree.  The fact that there is only one storage area to hold a single set of independent variables should be made crystal clear.  Also, that is a very important fact that should be explicitly made and easy to find.

I know I've seen it clearly documented somewhere but, I don't recall where.  Probably read it in some Pascal book or manual sometime years ago.

Maybe the omission or lack of clarity warrants a bug report against the documentation.  Like you, I am inclined to believe it does.
« Last Edit: November 01, 2024, 10:36:40 pm by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

simone

  • Hero Member
  • *****
  • Posts: 626
Re: Variant Record Behavior
« Reply #9 on: November 01, 2024, 11:15:35 pm »
In the book Oh Pascal by Doug Cooper and Michael Clancy, pages 413-414, there is a clear explanation of memory layout overlaying in variant records. Very nice book. (@440bx I remember you know this book  :))
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

440bx

  • Hero Member
  • *****
  • Posts: 4727
Re: Variant Record Behavior
« Reply #10 on: November 01, 2024, 11:31:41 pm »
Yes, I consider "Oh Pascal" one of the best programming books ever written, not only it teaches the language extremely well, it emphasizes good programming methodologies. 

Yes, excellent book. I'm glad you enjoy it too. :)

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 16139
  • Censorship about opinions does not belong here.
Re: Variant Record Behavior
« Reply #11 on: November 04, 2024, 11:13:33 am »
(Note that it says "unspecified" and not "undefined", which means it is implementation dependent, while "undefined" would mean it's never correct to read it out)
Well it is actually unspecified, especially when local. Stack is dirty, any excess memory is unspecified unless there is a fully filled alternative.
If I smell bad code it usually is bad code and that includes my own code.

Warfley

  • Hero Member
  • *****
  • Posts: 1734
Re: Variant Record Behavior
« Reply #12 on: November 04, 2024, 12:52:02 pm »
Well it is actually unspecified, especially when local. Stack is dirty, any excess memory is unspecified unless there is a fully filled alternative.
Not only that but also the standard is written in a way that makes it completely portable. But as soon as you talk memory layout things like endianess and stuff are very much hardware dependant. Which is why the C standard only allows you to treat memory regions as different types, if they are a strict prefix of one another. So the following is not standard C:
Code: C  [Select][+][-]
  1. typedef struct {
  2.   uint32_t a;
  3. } s1_t;
  4. typedef struct {
  5.   uint16_t w1, w2;
  6. } s2_t;
  7.  
  8. s1_t mystruct;
  9. (s2_t *)&mystruct->w1 = 42;
But the following is:
Code: C  [Select][+][-]
  1. typedef struct {
  2.   uint32_t a;
  3. } s1_t;
  4. typedef struct {
  5.   uint32_t a, b;
  6. } s2_t;
  7.  
  8. s2_t mystruct;
  9. (s1_t *)&mystruct->a = 42;
Because here you only "downsize" the record, and C guarantees the order of elements and layout of prefixes.

Anything else requires you to check with the behavior your compiler guarantees for the platform you are on.

 

TinyPortal © 2005-2018