Recent

Author Topic: Specify type of an array literal?  (Read 4566 times)

hayanninja

  • New Member
  • *
  • Posts: 45
Specify type of an array literal?
« on: December 31, 2017, 12:10:44 am »
So, to save myself some time (theoretically, at least), I've written a function:

Code: Pascal  [Select][+][-]
  1. type
  2.   TComponentArray = array of TComponent;
  3.  
  4.   procedure ProgressiveTag(aList: TComponentArray; aBase: Integer = 0);
  5.   var
  6.     i: Integer;
  7.   begin
  8.     for i := 0 to Length(aList)-1 do
  9.       aList[i].Tag := aBase + i;
  10.   end;

(I realise I could just directly hardcode the tags onto the form, but this makes it a bit easier if I need to change things later.)

The intention here is that I can do code like the following:
Code: Pascal  [Select][+][-]
  1. ProgressiveTag( [TabSheet1, TabSheet2, ...], 1);
  2. ProgressiveTag( [EditBox1, CheckBox1, ...], 0);

However - when I try to build this code, it says:
Code: [Select]
****.pas(92,83) Error: Incompatible type for arg no. 1: Got "{Array Of Const/Constant Open} Array of TComponent", expected "TComponentArray"
It seems that when the array is all the same type, it tries to interpret the literal as an array of this type. For example, if they're all TTabSheets, it interprets it as "array of TTabSheet" rather than "array of TComponent", despite that TTabSheet is a TComponent descendant. In fact, even if I mix them, or explicitly typecast some or even all elements to TComponent, it still has this issue:
Code: [Select]
****.pas(91,65) Error: Incompatible type for arg no. 1: Got "{Array Of Const/Constant Open} Array of TComponent", expected "TComponentArray"
If I try to typecast the array literal as a whole, I get this error:
Code: [Select]
****.pas(91,19) Error: Illegal type conversion: "{Array Of Const/Constant Open} Array of TTabSheet" to "TComponentArray"
If I recall correctly, an array literal can only be specified as a const if it has a fixed size, which these don't? I did think about definining consts rather than putting the array literals inline. Or is this something that will work in FPC / Lazarus and just not in Delphi? (I'm a very recent convert to Lazarus.)

So - what should I be doing here? Or is there simply no quick-and-easy way to do this and I should just do something a bit more manual?

(For the record, this is for an internal-use-only tool that I don't expect anyone but myself will ever use, so it doesn't really matter if it's not the most optimal code - being able to, in the long run, save time writing it is more important.)

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11455
  • FPC developer.
Re: Specify type of an array literal?
« Reply #1 on: December 31, 2017, 12:12:42 am »
TComponentArray.create([....]) maybe? But might be trunk only.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Specify type of an array literal?
« Reply #2 on: December 31, 2017, 12:20:24 am »
So, to save myself some time (theoretically, at least), I've written a function:

Code: Pascal  [Select][+][-]
  1. type
  2.   TComponentArray = array of TComponent;
  3.  
  4.   procedure ProgressiveTag(aList: TComponentArray; aBase: Integer = 0);
  5.   var
  6.     i: Integer;
  7.   begin
  8.     for i := 0 to Length(aList)-1 do
  9.       aList[i].Tag := aBase + i;
  10.   end;

(I realise I could just directly hardcode the tags onto the form, but this makes it a bit easier if I need to change things later.)

The intention here is that I can do code like the following:
Code: Pascal  [Select][+][-]
  1. ProgressiveTag( [TabSheet1, TabSheet2, ...], 1);
  2. ProgressiveTag( [EditBox1, CheckBox1, ...], 0);

However - when I try to build this code, it says:
Code: [Select]
****.pas(92,83) Error: Incompatible type for arg no. 1: Got "{Array Of Const/Constant Open} Array of TComponent", expected "TComponentArray"
It seems that when the array is all the same type, it tries to interpret the literal as an array of this type. For example, if they're all TTabSheets, it interprets it as "array of TTabSheet" rather than "array of TComponent", despite that TTabSheet is a TComponent descendant. In fact, even if I mix them, or explicitly typecast some or even all elements to TComponent, it still has this issue:
Code: [Select]
****.pas(91,65) Error: Incompatible type for arg no. 1: Got "{Array Of Const/Constant Open} Array of TComponent", expected "TComponentArray"
If I try to typecast the array literal as a whole, I get this error:
Code: [Select]
****.pas(91,19) Error: Illegal type conversion: "{Array Of Const/Constant Open} Array of TTabSheet" to "TComponentArray"
If I recall correctly, an array literal can only be specified as a const if it has a fixed size, which these don't? I did think about definining consts rather than putting the array literals inline. Or is this something that will work in FPC / Lazarus and just not in Delphi? (I'm a very recent convert to Lazarus.)

So - what should I be doing here? Or is there simply no quick-and-easy way to do this and I should just do something a bit more manual?

(For the record, this is for an internal-use-only tool that I don't expect anyone but myself will ever use, so it doesn't really matter if it's not the most optimal code - being able to, in the long run, save time writing it is more important.)
you need to declare your procedure as
Code: Pascal  [Select][+][-]
  1.   procedure ProgressiveTag(aList: array of TComponent; aBase: Integer = 0);
  2.   var
  3.     i: Integer;
  4.   begin
  5.     for i := 0 to Length(aList)-1 do
  6.       aList[i].Tag := aBase + i;
  7.   end;
in this case alist becomes an open array parameter which accepts any kind of TComponent arrays including variables declared as TComponentArray. TComponentArray on the other hand is a dynamic array of tcomponents not a open array and only accepts that dynamic array.
« Last Edit: December 31, 2017, 12:23:31 am by taazz »
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

hayanninja

  • New Member
  • *
  • Posts: 45
Re: Specify type of an array literal?
« Reply #3 on: December 31, 2017, 12:23:34 am »
you need to declare your procedure as
Code: Pascal  [Select][+][-]
  1.   procedure ProgressiveTag(aList: array of TComponent; aBase: Integer = 0);
  2.   var
  3.     i: Integer;
  4.   begin
  5.     for i := 0 to Length(aList)-1 do
  6.       aList[i].Tag := aBase + i;
  7.   end;
in this case alist becomes an open array parameter which accepts any kind of arrays including variables declared as TComponentArray. TComponentArray on the other hand is a dynamic array of tcomponents not a open array and only accepts that dynamic array.

I could swear that kind of code didn't work property in Delphi (though I might be confusing it with something else relating to arrays). But it works perfectly fine here, so thanks! :D

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: Specify type of an array literal?
« Reply #4 on: December 31, 2017, 04:22:23 am »
Try this this,..
Code: Pascal  [Select][+][-]
  1.  
  2.  
  3. procedure ProgressiveTag(aList: array of TComponent; aBase: Integer = 0);
  4.  
  5.  
  6. 2.  var
  7.  
  8.  
  9. 3.    i: Integer;
  10.  
  11.  
  12. 4.  begin
  13.  
  14.  
  15. 5.    for i := 0 to High(aList) do
  16.  
  17.  
  18. 6.      aList[i].Tag := aBase + i;
  19.  
  20.  
  21. 7.  end;
  22.  
  23.  
The only true wisdom is knowing you know nothing

Thaddy

  • Hero Member
  • *****
  • Posts: 14377
  • Sensorship about opinions does not belong here.
Re: Specify type of an array literal?
« Reply #5 on: December 31, 2017, 05:30:06 pm »
Or this in trunk:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. program undefined_symbol_bug;
  3. uses Classes, SysUtils;
  4. type
  5.   TComponentArray = array of TComponent;
  6.  
  7.   procedure ProgressiveTag(aList: TComponentArray; aBase: Integer = 0);
  8.   var
  9.     i: Integer;
  10.   begin
  11.     for i := Low(aList) to High(aList) do
  12.       aList[i].Tag := aBase + i;
  13.   end;
  14. var
  15.   a,b:TcomponentArray;
  16.   Tabsheet1,Tabsheet2,EditBox1,Checkbox1:Tcomponent;
  17. begin
  18.   a:=[TabSheet1, TabSheet2]; //uses new implicit dynamic array constructor syntax
  19.   ProgressiveTag(a, 1);
  20.   b:=[EditBox1, CheckBox1]; //uses new implicit dynamic array constructor syntax
  21.   ProgressiveTag(b, 0);
  22. end.
« Last Edit: December 31, 2017, 05:34:30 pm by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Specify type of an array literal?
« Reply #6 on: December 31, 2017, 08:30:38 pm »
you need to declare your procedure as
Code: Pascal  [Select][+][-]
  1.   procedure ProgressiveTag(aList: array of TComponent; aBase: Integer = 0);
  2.   var
  3.     i: Integer;
  4.   begin
  5.     for i := 0 to Length(aList)-1 do
  6.       aList[i].Tag := aBase + i;
  7.   end;
in this case alist becomes an open array parameter which accepts any kind of arrays including variables declared as TComponentArray. TComponentArray on the other hand is a dynamic array of tcomponents not a open array and only accepts that dynamic array.

I could swear that kind of code didn't work property in Delphi (though I might be confusing it with something else relating to arrays). But it works perfectly fine here, so thanks! :D
probably you refer to the result of a function eg
Code: Pascal  [Select][+][-]
  1. Type
  2.   TTagArray = array of TTag;
  3.  
  4. function GetTags(const aHtml:string):array of TTag;
  5. begin
  6. end;
  7.  
in this case "array of TTag" is invalid type but TTagArray is valid.
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

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: Specify type of an array literal?
« Reply #7 on: December 31, 2017, 08:48:25 pm »
if memory servers I think the LOW reports 0 in  earlier versions of FPC.

The only true wisdom is knowing you know nothing

Thaddy

  • Hero Member
  • *****
  • Posts: 14377
  • Sensorship about opinions does not belong here.
Re: Specify type of an array literal?
« Reply #8 on: December 31, 2017, 08:54:46 pm »
if memory servers I think the LOW reports 0 in  earlier versions of FPC.
Imho it is always better to use Low() and High() to iterate over  ranges or array indexes.
These compiler intrinsics have been there for decades. At least since TP.
Reason: you can't make mistakes like forgetting to X-1 or iterating over an array[100..199]:
Code: Pascal  [Select][+][-]
  1. program untitled;
  2. {$ifdef fpc}{$mode delphi}{$H+}{$I-}{$endif}
  3. var
  4.   a:array[100..199] of integer;
  5.   b:array['A'..'z'] of char;
  6. begin
  7.   writeln(Low(a):5,High(a):5);
  8.   writeln(Low(b):5,High(b):5);
  9. end.
So array indexes (wrong: it is indices, but everybody does it wrong nowadays) are ordinal types, not necessary integer types.....
Low(b) is impossibly 0.

I think you are confused with dynamic arrays: those are always zero based, indeed. This is still the case.
Use Low(), High(). Or for in do Always. You will be happy  :D

Happy New Year  8-) O:-)
« Last Edit: December 31, 2017, 09:20:30 pm by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5486
  • Compiler Developer
Re: Specify type of an array literal?
« Reply #9 on: January 02, 2018, 10:39:51 pm »
So, to save myself some time (theoretically, at least), I've written a function:

Code: Pascal  [Select][+][-]
  1. type
  2.   TComponentArray = array of TComponent;
  3.  
  4.   procedure ProgressiveTag(aList: TComponentArray; aBase: Integer = 0);
  5.   var
  6.     i: Integer;
  7.   begin
  8.     for i := 0 to Length(aList)-1 do
  9.       aList[i].Tag := aBase + i;
  10.   end;

(I realise I could just directly hardcode the tags onto the form, but this makes it a bit easier if I need to change things later.)

The intention here is that I can do code like the following:
Code: Pascal  [Select][+][-]
  1. ProgressiveTag( [TabSheet1, TabSheet2, ...], 1);
  2. ProgressiveTag( [EditBox1, CheckBox1, ...], 0);

With current trunk/3.1.1 this compiles without problems as there array constructors for dynamic arrays are supported. In 3.0.4 and earlier you can use the [...]-syntax in code (not declarations) only for sets and open array parameters (parameters declared as "array of ..." in the routine declarations).

 

TinyPortal © 2005-2018