Recent

Author Topic: Initializing Record with Array Content  (Read 3312 times)

local-vision

  • Jr. Member
  • **
  • Posts: 77
Re: Initializing Record with Array Content
« Reply #15 on: July 24, 2024, 07:32:51 pm »
Do you mean this?

 Hi cpicanco,

Yes, valid solution. Appriciated.

I have a long list of machine parameters (more than 90) that need to be controlled by control software that I am developing.

What I am attempting to achieve is the most simple/readable declaration of Constants and their direct initialization as possible. Minimizing any need to do any further variable declarations, processing/initialization, no for loops etc.
I have a long list of constants that each include records which contain the Machine Parameter attributes. Like this:

Code: Pascal  [Select][+][-]
  1. type
  2.  
  3. TPBA =record  
  4.  PDefault,PValue:Byte;
  5.  FPos:Integer;
  6.  Caption:String;
  7. end;
  8.  
  9. const
  10.  
  11. c_FTList                             :array[0..2] of String = ('Machine','A Setting','B Setting','Restore');
  12.  
  13. c_VM                                 :TPBA=(PDefault:2; PValue:2; FPos:24; Caption:'VIM Machine');
  14.  

What I would want is to add that c_FTList to that c_VM record as well.

But this does not work:

Code: Pascal  [Select][+][-]
  1. type
  2.  
  3. TPBA =record  
  4.  Default,Value:Byte;
  5.  FPos:Integer;
  6.  Caption:String;
  7.  PList:array of String; //added this to the record
  8. end;
  9.  
  10. const
  11.  
  12. c_FTList                             :array[0..2] of String = ('Machine','A Setting','B Setting','Restore');
  13.  
  14. c_VM                                 :TPBA=(PDefault:2; PValue:2; FPos:24; Caption:'VIM Machine'; PList:c_FTList); //does not work. any idea how to add the previously declared array?
  15.  

The reasoning to want to do this is organizational. It makes things easier to overview, modify, change later on when Machine Parameter attributes need to be changed.

Thaddy, sorry for your loss.

cdbc, not exactly able to follow.


cpicanco

  • Hero Member
  • *****
  • Posts: 655
  • Behavioral Scientist and Programmer
    • Portfolio
Re: Initializing Record with Array Content
« Reply #16 on: July 24, 2024, 11:41:54 pm »
local-vision, for low maintaince cost, I would use some sort of factory. For example:

Code: Pascal  [Select][+][-]
  1. unit MyType;
  2.  
  3. {$mode ObjFPC}{$H+}
  4. {$MODESWITCH ADVANCEDRECORDS}
  5.  
  6. interface
  7.  
  8. uses SysUtils, Generics.Collections;
  9.  
  10. type
  11.  
  12.   { TPBA }
  13.  
  14.   TMachine = (
  15.     Machine1,
  16.     Machine2,
  17.     Machine3,
  18.     Machine4
  19.   );
  20.  
  21.   TPBA = record
  22.     Default, Value : Byte;
  23.     Pos : Integer;
  24.     Caption : String;
  25.     List : TMachine;
  26.     function GetList : TStringArray;
  27.   end;
  28.  
  29.   TMachines = specialize TDictionary<TMachine, TStringArray>;
  30.  
  31. implementation
  32.  
  33. uses MyConstant;
  34.  
  35. var
  36.   Machines : TMachines;
  37.  
  38. function TPBA.GetList: TStringArray;
  39. begin
  40.   Result := Machines[Self.List];
  41. end;
  42.  
  43. initialization
  44.   Machines := TMachines.Create;
  45.   Machines.Add(Machine1, c_List1);
  46.   Machines.Add(Machine2, c_List2);
  47.   Machines.Add(Machine3, c_List3);
  48.   Machines.Add(Machine4, c_List4);
  49.  
  50. finalization
  51.   Machines.Free;
  52.  
  53. end.
  54.  

You may change code for configuration files, as you wish:

Code: Pascal  [Select][+][-]
  1. unit MyConstant;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses SysUtils, MyType;
  8.  
  9. const
  10.   c_List1 : TStringArray =
  11.     ('Machine1', 'A Setting', 'B Setting', 'Restore');
  12.  
  13.   c_List2 : TStringArray =
  14.     ('Machine2', 'A Setting', 'B Setting', 'Restore');
  15.  
  16.   c_List3 : TStringArray =
  17.     ('Machine3', 'A Setting', 'B Setting', 'Restore');
  18.  
  19.   c_List4 : TStringArray =
  20.     ('Machine4', 'A Setting', 'B Setting', 'Restore');
  21.  
  22.   c_VM1 : TPBA =
  23.     (Default: 2; Value: 2; Pos: 24; Caption: 'VIM Machine'; List: Machine1);
  24.  
  25.   c_VM2 : TPBA =
  26.     (Default: 2; Value: 2; Pos: 24; Caption: 'VIM Machine'; List: Machine2);
  27.  
  28.   c_VM3 : TPBA =
  29.     (Default: 2; Value: 2; Pos: 24; Caption: 'VIM Machine'; List: Machine3);
  30.  
  31.   c_VM4 : TPBA =
  32.     (Default: 2; Value: 2; Pos: 24; Caption: 'VIM Machine'; List: Machine4);
  33.  
  34. implementation
  35.  
  36. end.
  37.  
Project attached, what do you think?

Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. uses SysUtils, MyConstant, MyType;
  4.  
  5. var
  6.   VM : TPBA;
  7.   S : string;
  8.  
  9. begin
  10.   for VM in [c_VM1, c_VM2, c_VM3, c_VM4] do begin
  11.     for S in VM.GetList do begin
  12.       WriteLn(String.Join(#32, [VM.Caption, S]));
  13.     end;
  14.   end;
  15.   ReadLn;
  16. end.
  17.  
Be mindful and excellent with each other.
https://github.com/cpicanco/

TRon

  • Hero Member
  • *****
  • Posts: 3660
Re: Initializing Record with Array Content
« Reply #17 on: July 25, 2024, 12:14:24 am »
But this does not work:
The following does.

Code: Pascal  [Select][+][-]
  1. type
  2.   PStringArray = ^TStringArray;
  3.   TPBA =
  4.   record
  5.     PDefault,PValue:Byte;
  6.     FPos:Integer;
  7.     Caption:String;
  8.     list : PStringArray;
  9.   end;
  10.  
  11. const
  12.   c_FTList : TStringArray = ('Machine','A Setting','B Setting','Restore');
  13.   c_VM     : TPBA =
  14.     (
  15.       PDefault:2; PValue:2; FPos:24; Caption:'VIM Machine'; list: @C_FTList
  16.     );
  17.  
  18. begin
  19.   writeln(c_VM.list^[1]);
  20. end.
  21.  

And based on the idea of cpicano you could use a enum for the machine array and refer to that enum in your record. An additional record method/property could then hide the indirect access.
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

local-vision

  • Jr. Member
  • **
  • Posts: 77
Re: Initializing Record with Array Content
« Reply #18 on: July 25, 2024, 12:41:48 am »
So much appreciated! And, the project is valued, makes things more easy to understand.  :)

Lot to metabolize here, some new things to review. Will take a moment to study.
 

TRon

  • Hero Member
  • *****
  • Posts: 3660
Re: Initializing Record with Array Content
« Reply #19 on: July 25, 2024, 12:47:14 am »
Lot to metabolize here, some new things to review. Will take a moment to study.
It would also help if you are able to shed a light on whether the individual machine entries have a locked set of strings. Whether or not you want to have a complete machine list that contains all individual machine entries (or that you want to declare them separately), etc.

Right now you seem to be missing the difference regarding static and dynamic arrays.

A lot of your issues can be solved by simply declaring (and using) the right types.
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

cpicanco

  • Hero Member
  • *****
  • Posts: 655
  • Behavioral Scientist and Programmer
    • Portfolio
Re: Initializing Record with Array Content
« Reply #20 on: July 25, 2024, 12:59:13 am »
Just for cusiosity, why not:

Code: Pascal  [Select][+][-]
  1.   c_VM1: TPBA =
  2.     (
  3.       PDefault: 2;
  4.       PValue: 2;
  5.       FPos: 24;
  6.       Caption: 'VIM Machine';
  7.       list: ('Machine1', 'A Setting', 'B Setting', 'Restore')
  8.     );
  9.  
  10.   c_VM2: TPBA =
  11.     (
  12.       PDefault: 2;
  13.       PValue: 2;
  14.       FPos: 24;
  15.       Caption: 'VIM Machine';
  16.       list: ('Machine2', 'A Setting', 'B Setting', 'Restore')
  17.     );
Be mindful and excellent with each other.
https://github.com/cpicanco/

TRon

  • Hero Member
  • *****
  • Posts: 3660
Re: Initializing Record with Array Content
« Reply #21 on: July 25, 2024, 01:07:23 am »
Just for cusiosity, why not:
+1

I was assuming because the (same) machine definition is used multiple times in the record-list (e.g. why duplicate).

But as we all know assumption is the mother of all F-ups  :)
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

cpicanco

  • Hero Member
  • *****
  • Posts: 655
  • Behavioral Scientist and Programmer
    • Portfolio
Re: Initializing Record with Array Content
« Reply #22 on: July 25, 2024, 11:10:31 am »
I was assuming because the (same) machine definition is used multiple times in the record-list (e.g. why duplicate).

Instead of assumptions, lets say creativity exercise (or "brainstorm", "benchmark" if you are a market oriented person) aimed at finding breaking errors as soon as possible and avoid them.

So, my suggestion is to use configuration files (ini, json, yaml, whatever) to save list like machine configurations. This way you can save a lot of work doing stuff outside code if you have a frequently changing/growing setup. Using a design pattern (a factory) to initialize them into typed constants would save a lot of work inside the IDE, you could even improve the strategy to load new types from files too if you find it useful.

You mentioned "choosing the right type". You suggested pointers, correct? Would you choose them for performance? I am kind of afraid of pointers. I know they are powerful. But I am used to break my code use them  :D.
« Last Edit: July 25, 2024, 11:32:06 am by cpicanco »
Be mindful and excellent with each other.
https://github.com/cpicanco/

local-vision

  • Jr. Member
  • **
  • Posts: 77
Re: Initializing Record with Array Content
« Reply #23 on: July 25, 2024, 01:35:04 pm »
Much appreciate the input.

It would also help if you are able to shed a light on whether the individual machine entries have a locked set of strings.

If you are referring to the lists: each list may have a different count of strings. One list may only have 2 strings while the other 8. So static arrays seem not applicable.

Right now you seem to be missing the difference regarding static and dynamic arrays.

A lot of your issues can be solved by simply declaring (and using) the right types.

Much Agreed.

To be clear:

The emphasis here is to find out if I can declare all Machine Parameters (as constants or variables) and initialize each of their record elements at design time in the most simple, clear and over-viewable way possible.

I believe that I have achieved that with exception to being able to add a pre-declared list of strings as record element.

This seems to work:
Code: Pascal  [Select][+][-]
  1. Type
  2.  
  3. TPBA =record  
  4.  Default,Value:Byte;
  5.  FPos:Integer;
  6.  Caption:String;
  7.  PList:array of String;
  8. end;
  9.  
  10. const //could also be var
  11.  
  12. c_VM0    :TPBA=(PDefault:3; PValue:89; FPos:0; Caption:'VIM0 Machine'; PList: 'Module','K Setting')
  13. c_VM1    :TPBA=(PDefault:2; PValue:2; FPos:1; Caption:'VIM1 Machine'; PList: 'Machine','A Setting','B Setting','Restore');
  14.  

But I rather have this (which does not seem to work):

Code: Pascal  [Select][+][-]
  1. Type
  2.  
  3. TPBA =record  
  4.  Default,Value:Byte;
  5.  FPos:Integer;
  6.  Caption:String;
  7.  PList:array of String;
  8. end;
  9.  
  10. const //could also be var
  11.  
  12. c_FTList0    :array[0..1] of String = ('Module','K Setting');
  13. c_FTList1    :array[0..2] of String = ('Machine','A Setting','B Setting','Restore');
  14.  
  15. c_VM0         :TPBA=(PDefault:3; PValue:89; FPos:0; Caption:'VIM0 Machine'; PList: c_FTList0); //error
  16. c_VM1         :TPBA=(PDefault:2; PValue:2; FPos:1; Caption:'VIM1 Machine'; PList: c_FTList1); //error
  17.  

But that or something similair might not be possible.
« Last Edit: July 25, 2024, 02:02:52 pm by local-vision »

Khrys

  • Full Member
  • ***
  • Posts: 109
Re: Initializing Record with Array Content
« Reply #24 on: July 25, 2024, 03:26:10 pm »
TRon's solution using pointers comes closest to what you're trying to achieve. If you're using  {$mode delphi}  or  {$modeswitch autoderef} you won't even have to explicitly dereference anything:

Code: Pascal  [Select][+][-]
  1. {$modeswitch autoderef}
  2.  
  3. type
  4.   PStringArray = ^TStringArray;
  5.   TPBA = record
  6.     PDefault, PValue: Byte;
  7.     FPos: Integer;
  8.     Caption: String;
  9.     PList: PStringArray;
  10.   end;
  11.  
  12. const
  13.   c_FTList0: TStringArray = ('Module', 'K Setting');
  14.   c_FTList1: TStringArray = ('Machine', 'A Setting', 'B Setting', 'Restore');
  15.   c_VM0: TPBA = (PDefault: 3; PValue: 89; FPos: 0; Caption: 'VIM0 Machine'; PList: @c_FTList0);
  16.   c_VM1: TPBA = (PDefault: 2; PValue: 2; FPos: 1; Caption: 'VIM1 Machine'; PList: @c_FTList1);
  17.  
  18. begin
  19.   WriteLn(c_VM0.PList[1]); // 'K Setting'
  20. end.

Regarding arrays it's important to know that sized and dynamic arrays work in a completely different manner under the hood; the former actually directly contains all of its elements, while the latter is just a pointer to reference-counted memory:

Code: Pascal  [Select][+][-]
  1. var
  2.   FixedSize: array[0..7] of Int64;
  3.   DynamicSize: array of Int64;
  4. begin
  5.   SetLength(DynamicSize, 8);
  6.   WriteLn(SizeOf(FixedSize));    // 64
  7.   WriteLn(SizeOf(DynamicSize));  // SizeOf(Pointer); 8 if running on a 64-bit CPU, 4 on 32 bits, etc.
  8. end.

TRon

  • Hero Member
  • *****
  • Posts: 3660
Re: Initializing Record with Array Content
« Reply #25 on: July 25, 2024, 04:27:09 pm »
Instead of assumptions, lets say creativity exercise (or "brainstorm", "benchmark" if you are a market oriented person) aimed at finding breaking errors as soon as possible and avoid them.
Sure thing but TS hasn't mention anything in that regards. Personally I'm in lazy mode by default  :)

Quote
So, my suggestion is to use configuration files (ini, json, yaml, whatever) to save list like machine configurations.
...
Depends on the use case but you have a point.

Quote
You mentioned "choosing the right type". You suggested pointers, correct? Would you choose them for performance?
The remark about the right type was about declaring the right types and make use of the right types as  there is quite a difference between static and dynamic arrays. Also note that TS' example snippets are riddled with errors.

I've opted for a pointer for two reasons:
- to stay as close to the answer that TS seems to be looking for
- These parameters/records might be static, though the proposed solution allows for them to be expanded.

I am aware that your suggestion(s) are more future proof and flexible, e.g. there is nothing wrong with it and perhaps even preferable.

The lack of crystal balls might have influenced my answer  ;)

Quote
I am kind of afraid of pointers. I know they are powerful. But I am used to break my code use them  :D.
Under the hood your dictionary solution uses even more pointers but I digress.

There are use cases where pointers are simply quicker to setup and/or work with (jump tables comes to mind).
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

TRon

  • Hero Member
  • *****
  • Posts: 3660
Re: Initializing Record with Array Content
« Reply #26 on: July 25, 2024, 04:49:01 pm »
But that or something similair might not be possible.
Literally as you suggest, no that is not possible.

But see the example from Krysh in post#24 which is as close as it can be.

Besides the inclusion of the machine parameters as suggested by cpicanco in post#20 that are the only two ways that I am aware of that stays as close to your original example.

As cpicanco suggested, there are better solutions but they might or might not be relevant for your (specific) use case.

You are the only person that is able to decide that without us knowing more about the use case and/or the presence of a more complete example.

« Last Edit: July 25, 2024, 04:51:34 pm by TRon »
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

local-vision

  • Jr. Member
  • **
  • Posts: 77
Re: Initializing Record with Array Content
« Reply #27 on: July 25, 2024, 09:34:20 pm »
Khrys, TRon, cpicanco : Full appreciation.

Again this is part of what makes Lazarus so powerful and keeps Wirth's spirit alive; the community.

I can move forward now with the insight that you have provided. The example Krysh in post#24 is the closest to what I would want.

The issue here is indeed not just technical but also legacy code aspects/requirements that I am facing that need to be retained.

my suggestion is to use configuration files (ini, json, yaml, whatever) to save list like machine configurations. This way you can save a lot of work doing stuff outside code if you have a frequently changing/growing setup. Using a design pattern (a factory) to initialize them into typed constants would save a lot of work inside the IDE, you could even improve the strategy to load new types from files too if you find it useful.


That is what I need to hear. Good idea. It may allow me to work around certain constraints.

It seems that this:

Code: Pascal  [Select][+][-]
  1.  WriteLn(c_VM0.PList[1]); // 'K Setting'

Needs to be this:

Code: Pascal  [Select][+][-]
  1.  WriteLn(c_VM0.PList[0,1]); // 'K Setting'

In order to work.

The TStringArray is 2 dimensional?
« Last Edit: July 26, 2024, 12:53:42 pm by local-vision »

 

TinyPortal © 2005-2018