Recent

Author Topic: I don't understand Pascal record syntax  (Read 1507 times)

giahung1997

  • Full Member
  • ***
  • Posts: 113
I don't understand Pascal record syntax
« on: May 19, 2019, 08:40:35 pm »
I'm serious not trolling. The simple record is fine but the advanced with case boolean of, I really don't understand. It's a record, right? What does case boolean of do here? Something is wrong here, like having switch statement inside C struct. It's looks complicated. Please explain.
Hate me? I'm gone. You will never see me again. Fuck the people of this forum! Fuck this Lazarus! Fuck Pascal!

giahung1997

  • Full Member
  • ***
  • Posts: 113
Re: I don't understand Pascal record syntax
« Reply #1 on: May 19, 2019, 08:55:44 pm »
http://wiki.freepascal.org/Record

Sorry I overlooked it. Solved.
Hate me? I'm gone. You will never see me again. Fuck the people of this forum! Fuck this Lazarus! Fuck Pascal!

lucamar

  • Hero Member
  • *****
  • Posts: 2018
Re: I don't understand Pascal record syntax
« Reply #2 on: May 19, 2019, 09:56:11 pm »
In case it isn't clear and since you seem to know C, the variant part in a record (that case of ...) is somehow like declaring a union as member of a struct in C.

With quite a few sintactical differences, of course :)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.2/2.0.4  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

Thausand

  • Full Member
  • ***
  • Posts: 234
Re: I don't understand Pascal record syntax
« Reply #3 on: May 19, 2019, 10:54:07 pm »
Is many more easy understand if make do and not alone read  ;D

If want alone read and compare union c then maybe read this http://www.delphicorner.f9.co.uk/articles/op6.htm

lucamar

  • Hero Member
  • *****
  • Posts: 2018
Re: I don't understand Pascal record syntax
« Reply #4 on: May 19, 2019, 11:16:31 pm »
Is many more easy understand if make do and not alone read  ;D

Yes, of course :)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.2/2.0.4  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

kveroneau

  • Jr. Member
  • **
  • Posts: 72
Re: I don't understand Pascal record syntax
« Reply #5 on: June 04, 2019, 05:01:08 pm »
Here's an example I wrote in some of my code, then it immediately clicked on how it works:

Code: Pascal  [Select]
  1. type
  2.   TFlags = bitpacked record
  3.     Carry, Zero, Interrupt, Decimal, Break, NotUsed, Overflow, Negative: Boolean;
  4.   end;
  5.   TCPUFlags = packed record
  6.     case Integer of
  7.       0: (Reg: Byte);
  8.       1: (Flag: TFlags);
  9.   end;
  10.  
  11. var
  12.   regP: TCPUFlags
  13.  
  14. begin
  15.   regP.Flag.Zero:=True;
  16.   WriteLn(regP.Reg);
  17. end.
  18.  

Basically, it allows you to access the same memory location in 2 different ways, in this example, since a byte is 8 bits(or packed booleans), each bit in the byte in memory can be accessed using an identifier as seen above.  We can then access the complete 8-bits as a fully fledged byte, which will reflect the bit changes we made to the booleans.  If your more of an Intel coder, here's a better example:

Code: Pascal  [Select]
  1. type
  2.   TAXRegister = record
  3.     AL, AH: Byte;
  4.   end;
  5.   TCPURegister = packed record
  6.     case Integer of
  7.       0: (AX: Word);
  8.       1: (Reg: TAXRegister);
  9.   end;
  10.  
  11. var
  12.   regAX: TCPURegister;
  13.  
  14. begin
  15.   regAX.AX:=1024;
  16.   WriteLn(RegAX.Reg.AL); // Will display 4.
  17. end.
  18.  

I didn't test the above code, but it *should* work, and is more for example purposes.  I think there is a way to embed everything together as well.

furious programming

  • Sr. Member
  • ****
  • Posts: 354
  • I click a little.
Re: I don't understand Pascal record syntax
« Reply #6 on: June 05, 2019, 03:47:01 pm »
I think there is a way to embed everything together as well.

Yes, you can declare a field as record directly inside the declaration of the main record:

Code: Pascal  [Select]
  1. type
  2.   TCPUFlags = bitpacked record
  3.     case Integer of
  4.       0: (Reg: Byte);
  5.       1: (Flags: record
  6.             Carry: Boolean;
  7.             Zero: Boolean;
  8.             Interrupt: Boolean;
  9.             Decimal: Boolean;
  10.             Break: Boolean;
  11.             NotUsed: Boolean;
  12.             Overflow: Boolean;
  13.             Negative: Boolean;
  14.           end);
  15.   end;
  16.  

And the same in second example:

Code: Pascal  [Select]
  1. type
  2.   TCPURegister = packed record
  3.     case Integer of
  4.       0: (AX: Word);
  5.       1: (Reg: record
  6.             AL: Byte;
  7.             AH: Byte;
  8.           end);
  9.   end;
  10.  
« Last Edit: June 05, 2019, 04:56:25 pm by furious programming »
Lazarus 2.0.4 with FPC 3.0.4, Windows XP (all 32-bit)

ASerge

  • Hero Member
  • *****
  • Posts: 1408
Re: I don't understand Pascal record syntax
« Reply #7 on: June 06, 2019, 04:49:56 pm »
Code: Pascal  [Select]
  1. type
  2.   TAXRegister = record
  3.     AL, AH: Byte;
  4.   end;
  5.   TCPURegister = packed record
  6. ...
In the first case it is better to put the word "packed", and in the second case-not necessarily. For example, in Delphi 10.3 Implicit Packing of Fields with a Common Type Specification work only with {$OLDTYPELAYOUT ON} directive.

Yes, you can declare a field as record directly inside the declaration of the main record:
I have not seen documentation that says that the word (bit)packed also applies to nested record types. Yes, now it works because of the compatibility with Delphi, but it does not look logical. After all, if you declare a nested structure as a separate type, that is, without words packed, and use it already in the declaration, you will get a different result. So I think this type declaration is wrong, i.e. you must write (bit)packed for both "record".

And in my opinion better is such a type declaration:
Code: Pascal  [Select]
  1. TFlags = set of (Carry, Zero, Interrupt, Decimal, Break, NotUsed, Overflow, Negative);
Moreover, the code like "Include(Set, Flag)" or "if Flag in Set then" is not only more readable, but also more efficient.

giahung1997

  • Full Member
  • ***
  • Posts: 113
Re: I don't understand Pascal record syntax
« Reply #8 on: June 07, 2019, 09:35:47 am »
It's difficult for me to understand at first because I used to C's implication style. Pascal is more verbose about this so the syntax seems somewhat alien.

https://www.tutorialspoint.com/cprogramming/c_unions.htm

I'm a style of people doesn't care about clean or correctness but just works is fine. So I like C union more but acknowledge many years later when I'm old and not programming for a long time, I would prefer Pascal style.
Hate me? I'm gone. You will never see me again. Fuck the people of this forum! Fuck this Lazarus! Fuck Pascal!

furious programming

  • Sr. Member
  • ****
  • Posts: 354
  • I click a little.
Re: I don't understand Pascal record syntax
« Reply #9 on: June 07, 2019, 04:11:51 pm »
I have not seen documentation that says that the word (bit)packed also applies to nested record types. Yes, now it works because of the compatibility with Delphi, but it does not look logical.

It is logical and it should work in this way. If the main record is marked as packed or bitpacked, its entire content should be packed — if the subrecord are declared directly, not as an external type.

Although for the sake of uniformity, this internal record can also be declared as packed or bitpacked.

Quote
After all, if you declare a nested structure as a separate type, that is, without words packed, and use it already in the declaration, you will get a different result.

And this behavior is also correct. Both are correct and logical.


Quote
Moreover, the code like "Include(Set, Flag)" or "if Flag in Set then" is not only more readable […]

No, it is not readable and it is not convenient to use, just like using the Inc, Dec, Length and other ancient subroutines. And it does not give you the option to set a flag based on any type other than TFlags, which is undesirable because it is limiting.

But the set of flags can be used together with boolean flags. If I declare the types for example in this way:

Code: Pascal  [Select]
  1. {$MODE OBJFPC}
  2.  
  3. {$PACKSET 1}
  4. {$PACKENUM 1}
  5.  
  6. type
  7.   TEnumFlag = (Carry, Zero, Interrupt, Decimal, Break, NotUsed, Overflow, Negative);
  8.   TEnumFlags = set of TEnumFlag;
  9.  
  10. {$PACKSET DEFAULT}
  11. {$PACKENUM DEFAULT}
  12.  
  13. type
  14.   TBoolFlags = bitpacked record
  15.     Carry: Boolean;
  16.     Zero: Boolean;
  17.     Interrupt: Boolean;
  18.     Decimal: Boolean;
  19.     Break: Boolean;
  20.     NotUsed: Boolean;
  21.     Overflow: Boolean;
  22.     Negative: Boolean;
  23.   end;
  24.  
  25. type
  26.   TCPUFlags = bitpacked record
  27.     case Integer of
  28.       0: (Byte: Byte);
  29.       1: (Bool: TBoolFlags);
  30.       2: (Enum: TEnumFlags);
  31.   end;
  32.  
  33. var
  34.   CPUFlags: TCPUFlags;

then I can initialize the state of flags by assigning the whole set:

Code: Pascal  [Select]
  1. CPUFlags.Enum := [Interrupt, Decimal];

If I need to include or exclude some flags, I can use the += and -= operator:

Code: Pascal  [Select]
  1. CPUFlags.Enum += [NotUsed, Overflow];
  2. CPUFlags.Enum -= [Decimal];

I can get or set the state of flags as a number without having to cast:

Code: Pascal  [Select]
  1. IntValue := CPUFlags.Byte;

and if I need it, I can set each flag separately based on testing values of any type:

Code: Pascal  [Select]
  1. CPUFlags.Bool.Break := IntValue <> 0;

or assigning a specific logical value without testing. And if I need to check if the flag is set, I can read the logical value directly, without testing:

Code: Pascal  [Select]
  1. if CPUFlags.Bool.Interrupt then

Easy to use, readable and functional.


Quote
[…] but also more efficient.

In both cases reading the state of the flag (bit) boils down to conjunction and comparison to 0. However, such a simple case (a primitive operation) should be optimized by the optimizer, not by the programmer.
« Last Edit: June 09, 2019, 05:21:57 pm by furious programming »
Lazarus 2.0.4 with FPC 3.0.4, Windows XP (all 32-bit)

Thaddy

  • Hero Member
  • *****
  • Posts: 8919
Re: I don't understand Pascal record syntax
« Reply #10 on: June 07, 2019, 07:23:40 pm »
The set approach is actually nicer: sets can be bitpacked too:
Code: Pascal  [Select]
  1. {$mode objfpc}
  2. var
  3.    testset: bitpacked set of boolean = []; // this is trivial, but the above can be completely reworked using set , range and enum types.
  4. begin end.

I use similar code for the Raspberry Pi GPIO. You can bring up/down or test multiple pins in one go using set operations. The result is very clean code.
« Last Edit: June 07, 2019, 07:45:56 pm by Thaddy »
Most people that want to use threading should learn to patch their jeans first: use a needle.

furious programming

  • Sr. Member
  • ****
  • Posts: 354
  • I click a little.
Re: I don't understand Pascal record syntax
« Reply #11 on: June 09, 2019, 05:24:44 pm »
@Thaddy: can you show me a practical example of using such a set? Any pros and cons?
Lazarus 2.0.4 with FPC 3.0.4, Windows XP (all 32-bit)

jamie

  • Hero Member
  • *****
  • Posts: 1990
Re: I don't understand Pascal record syntax
« Reply #12 on: June 09, 2019, 05:56:16 pm »
one example which I use is to write a bitpacked set of Boolean out to file in a INI file for example.

I can have 32 Booleans but read and write it as a single DWord or integer out to file.

If there are more than 32 Booleans in the set then I could use the Binary method to write it
to file and still use only a single Key name in the file for it..


Thaddy

  • Hero Member
  • *****
  • Posts: 8919
Re: I don't understand Pascal record syntax
« Reply #13 on: June 10, 2019, 09:00:47 am »
@Thaddy: can you show me a practical example of using such a set? Any pros and cons?
Code: Pascal  [Select]
  1. {$mode objfpc}
  2. // suppose 8 pins...
  3. type
  4.   Pin = (p1,p2,p3,p4,p5,p6,p7,p8);
  5.   Pins = bitpacked set of pin;  
  6. var
  7.   // This is a dummy
  8.   SomeHardwareAddress:byte = 0; // 8 pins, so change to a max of 255 pins when necessary
  9.   B,C:Pins;
  10.   D:Pins absolute SomeHardwareAddress;  // in real life define this as an immediate address, like $B8200000
  11.   A:Pin;
  12. begin
  13.   B :=[p4,p5,p6];
  14.   C :=[P2, p5];
  15.   // operates on two sets of pin
  16.   D := B >< C;
  17.   // set pin on if it is not on
  18.   include(C, P7);
  19.   // set pin off if not off
  20.   exclude(C, p2);
  21.   writeln('Symetric difference');
  22.   for a in D do
  23.     writeln(a, ord(a)+1:4);
  24.   // operates on two sets of pin at once  
  25.   D := B * C ;
  26.   writeln('intersection');
  27.    for a in D do
  28.      writeln(a, ord(a)+1:4);
  29.   writeln('Union');
  30.   D:= C+B;
  31.   for a in D do
  32.     writeln(a, ord(a)+1:4);
  33.   writeln('Difference');
  34.   D:= B-C;
  35.   for a in D do
  36.     writeln(a, ord(a)+1:4);
  37.   // check the pins (right to left)
  38.   writeln('check the pins (right to left)');  
  39.   writeln(binstr(SomeHardwareAddress,8));
  40. end.

PRO's:
- All set operators apply
- Pin layout is as the hardware is layed out, It can be represented as an Unsigned byte too in my example, by a cast. This is because it is a bitpacked set.
- The enumeration can be based on actual pin functionality names.
- Pin On/Of flip/flop can achieved by with the real pin names from the enumeration and include exclude as well ass the difference operators (as above: all set operators apply).
- Mutiple pins can be set to on/of at once.
- Bit testing with in for single bits and <= for multiple bits operators
- Pins associated with more than one bit - that happens - can be operated on with sub sets. (e.g. on a raspberry pi). And you can type the subsets with meaningful names
- All in all fast, flexible and therefor powerful.
- Such flexibility can't easily be achieved in languages like C/C++/any language that does not natively support sets.
- Less error prone than other solutions.
- Doesn't rely on any other units!!

CON
-  Not many people really understand the more advanced set operators......But you can fold them into inline procedures and functions to make it more comprehensible for the many....
- example is procedural, but you can put it in a class with all class methods (hardware address is fixed..) or an advanced record.

(Modified the example a bit later).

If this is not clear enough I can give you an example based on the Raspberry Pi GPIO (but that is atm not very clean, since I change it too much and it is not under version control, unlike most of my code)
« Last Edit: June 10, 2019, 12:54:45 pm by Thaddy »
Most people that want to use threading should learn to patch their jeans first: use a needle.

Thaddy

  • Hero Member
  • *****
  • Posts: 8919
Re: I don't understand Pascal record syntax
« Reply #14 on: June 10, 2019, 01:20:30 pm »
I will add it to the wiki when it is functional again.
Most people that want to use threading should learn to patch their jeans first: use a needle.