Recent

Author Topic: The Variable Part of Record  (Read 5163 times)

FallingStar

  • Newbie
  • Posts: 6
The Variable Part of Record
« on: October 08, 2015, 09:40:17 am »
I am new to Pascal. After reading the wiki, I can not understand what is the core of Variable structure. I mean:
 - What does the "case ... of" statement do? What is its effect? Because according to me testing, nothing happend if I don't assign ''identifier'' of one of the constants.
 - Why do all of the fields have the same value (when debugging)?
 - How to use the variable structure?
I'm pretty confused. And in contrast to the wiki, it DOES harm to define one field multiple times, since it won't let you compile (FPC 2.6.4).
Thanks in advance.


eny

  • Hero Member
  • *****
  • Posts: 1634
Re: The Variable Part of Record
« Reply #1 on: October 08, 2015, 10:12:15 am »
have a look at the TRect structure and see how it works.
All posts based on: Win10 (Win64); Lazarus 2.0.10 'stable' (x64) unless specified otherwise...

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: The Variable Part of Record
« Reply #2 on: October 08, 2015, 10:25:58 am »
a variable part of a record is simple mechanism to allow to access the common memory location of that record with different type of variables for example.
Code: Delphi  [Select][+][-]
  1. type
  2.   TMyLongInt = record
  3.     case integer of
  4.       1 : (LongNo : LongInt);
  5.       2 : (Bytes  : Array [0..3] of Byte);
  6.       3 : (Words  : Array [0..1] of Word);
  7.       4 : (Chars  : Array [0..3] of Char);
  8.   end;
  9.  
This is a variable record of 1 field with a size of 4 bytes those bytes can be accessed as either a single longint an array of bytes, words or characters depending on your needs. The idea is to reuse the same memory for what ever you might need depending on the flow of your application instructing the compiler to enforce the type's rules for accessing the memory.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

FallingStar

  • Newbie
  • Posts: 6
Re: The Variable Part of Record
« Reply #3 on: October 08, 2015, 01:22:03 pm »
Thank you for replying.
I have more questions:
  - What does the "integer" and the constants do? Or they are just purely asthetics?
  - What if the size of the variants are not the same? There will be common and uncommon bytes right?

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: The Variable Part of Record
« Reply #4 on: October 08, 2015, 02:09:08 pm »
- What does the "integer" and the constants do? Or they are just purely asthetics?
In a way the 'integer' part is aesthetic, but it can be practical. as well.

What if you would only have two different 'unions' ? Then you could use a boolean (true and false value). Taazz could just as well had used a byte value for his example (but he didn't  :P )

The used constants, well (in this case) they need to match the integer type and be unique for each variable part that you want to declare.

Would taazz have used this form:
Code: [Select]
  TMyLongInt = record
    case boolean of
    true  : (LongNo : LongInt);
    false : (Bytes  : Array [0..3] of Byte);
    ?? : (Words  : Array [0..1] of Word);
    ?? : (Chars  : Array [0..3] of Char);
  end;
.. then the boolean identifier wouldn't offer enough different values to complete the structure, ergo he used a longint to make sure this structure can grow, and is future proof as it now offers more constants to be used in order to extend the structure even further (do try that yourself and see).

Quote
- What if the size of the variants are not the same? There will be common and uncommon bytes right?
Yes.

In fact you could for instance use the first byte in the record to define/recognize 255 different definitions of your record (or a word for even more).

You are _allowed_ to use common fields as taazz showed (those that actually make sense), but you could just as well make 255 completely different structures inside the record with using the first byte to determine it's structure programmatically.

For instance, make the char array 6 bytes instead of 4 as taazz showed. If you do a WriteLn(sizeOf(TMyLongInt)) you'll notice that the record isn't 4 bytes anymore, but grows to being 6 bytes (or perhaps even 8/16 depending on the alignment of the record fields). In variable records, the record size becomes the size of the 'biggest' structure that is needed to store all the fields into memory.

I would really encourage you to play with simple things like WriteLn, to see what it actually does in practice.

One for the road  :D
Code: Pascal  [Select][+][-]
  1. program variable_record;
  2.  
  3. Uses
  4.   SysUtils;
  5.  
  6. Type
  7.   TMyLongInt = record
  8.     case integer of
  9.     1 : (LongNo : LongInt);
  10.     2 : (Bytes  : Array [0..3] of Byte);
  11.     3 : (Words  : Array [0..1] of Word);
  12.     4 : (Chars  : Array [0..3] of Char);
  13.   end;
  14. Var
  15.   MyLongInt : TMyLongInt;
  16.  
  17. begin
  18.   {$IFDEF ENDIAN_LITTLE}
  19.   MyLongInt.LongNo := $6C6F6F43;
  20.   {$ELSE}
  21.   MyLongInt.LongNo := $436F6F6C;  
  22.   {$ENDIF}
  23.  
  24.   With MyLongInt do
  25.   begin
  26.     WriteLn('LongNo   = #', LongNo  , ' = $', IntToHex(LongNo  , SizeOf(LongInt)));
  27.  
  28.     WriteLn('Words[0] = #', Words[0], ' = $', IntToHex(Words[0], SizeOf(Word)));
  29.     WriteLn('Words[1] = #', Words[1], ' = $', IntToHex(Words[1], SizeOf(Word)));
  30.  
  31.  
  32.     WriteLn('Bytes[0] = #', Bytes[0], ' = $', IntToHex(Bytes[0], SizeOf(Byte)));
  33.     WriteLn('Bytes[1] = #', Bytes[1], ' = $', IntToHex(Bytes[1], SizeOf(Byte)));
  34.     WriteLn('Bytes[2] = #', Bytes[2], ' = $', IntToHex(Bytes[2], SizeOf(Byte)));
  35.     WriteLn('Bytes[3] = #', Bytes[3], ' = $', IntToHex(Bytes[3], SizeOf(Byte)));
  36.  
  37.     Writeln('Chars    = ', Chars);
  38.   end;
  39. end.
  40.  
« Last Edit: October 08, 2015, 02:28:02 pm by molly »

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: The Variable Part of Record
« Reply #5 on: October 08, 2015, 04:02:10 pm »
Thank you for replying.
I have more questions:
  - What does the "integer" and the constants do? Or they are just purely asthetics?
  - What if the size of the variants are not the same? There will be common and uncommon bytes right?
just to clarify a couple of things on top of what molly just said.
a Record is a continues block of memory it will always be big enough to hold the biggest variable record you specify but not bigger. There is no such thing as common and and uncommon parts all the memory used by the record can be access. Thing of it like a painting that depending of the colored filter you put in front of it it will show you different things that might or might not be visible in different colored filters.
I am reluctant to use the word common and un common because a record can have a static part which is usually referred to as common part and a variable part for example.
Code: Delphi  [Select][+][-]
  1. type
  2.   TMyContact = record
  3.     CntID   : int64;
  4.     CntType : Byte;
  5.     cntAddress : string[200];
  6.     case byte of
  7.       1 : (cntName  : string[200] );
  8.       2 : (cntFName : string[50]; cntMname :string[50]; cntLName:string[100]);
  9.   end;
  10.  
The fields CntId, CntType and CntAddress are referred to as the common part of the record they are the same regardless of the variable part. The variable part its supposed to hold both a person's name and a companies name depending on the CntType eg 0 = person, 1 = company etc.
so the last 203 bytes of the record are accessed (or viewed) differently depending on the value the CntType has it can either be a single continues company name or it can hold the 3 usual parts of a person's name. AS you can see things are a bit flexible. Keep in mind that the compiler will make sure that you can access the memory represented by the variable record in one of the two ways you specified regardles of what the cntType contents are. That means that your application is responsible of accessing the data through the correct fields the compiler will not stop accessing them the wrong way. Also there is no way (that I know of) to specify a correlation between a fields value and the constant value of the case statement the two are always unrelated.

Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: The Variable Part of Record
« Reply #6 on: October 08, 2015, 04:36:08 pm »
Keep in mind that the compiler will make sure that you can access the memory represented by the variable record in one of the two ways you specified regardles of what the cntType contents are. That means that your application is responsible of accessing the data through the correct fields the compiler will not stop accessing them the wrong way.
Or you can do it with "case hasAllFields: Boolean of" so you know which type is stored:
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyContact = record
  3.     CntID   : int64;
  4.     CntType : Byte;
  5.     cntAddress : string[200];
  6.     case hasAllFields: Boolean of
  7.       false : (cntName  : string[200] );
  8.       true  : (cntFName : string[50]; cntMname :string[50]; cntLName:string[100]);
  9.   end;

This will not stop you from using either cntName or cntFName/cntMname/cntLName but at least you have an extra variable in there (hasAllFields) which you can fill with the correct value of which one you used.

This would be equivalent but with previous example it's more clear what the function of hasAllFields is.
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyContact = record
  3.     CntID   : int64;
  4.     CntType : Byte;
  5.     cntAddress : string[200];
  6.     hasAllFields: Boolean;
  7.     case Boolean of
  8.       false : (cntName  : string[200] );
  9.       true  : (cntFName : string[50]; cntMname :string[50]; cntLName:string[100]);
  10.   end;

 

TinyPortal © 2005-2018