Recent

Author Topic: multi-dimensional open array parameter?  (Read 21019 times)

photor

  • New Member
  • *
  • Posts: 49
multi-dimensional open array parameter?
« on: May 30, 2014, 04:37:51 pm »
According to http://www.freepascal.org/docs-html/ref/refsu64.html, functions in free pascal can use open array parameters, as
Code: [Select]
Function Average (Row : Array of integer) : Real;to match any size of ONE-DIMENSIONAL arrays.
But if I try to define a function with two-dimensional open array parameter, as
Code: [Select]
Function Average (Row : Array of Array of integer) : Real;, the compiler will prompt
Quote
Error: Type identifier expected
. So, how can I do this?
« Last Edit: May 30, 2014, 04:40:13 pm by photor »

Blaazen

  • Hero Member
  • *****
  • Posts: 2782
  • POKE 54296,15
    • Eye-Candy Controls
Re: multi-dimensional open array parameter?
« Reply #1 on: May 30, 2014, 04:50:58 pm »
You can use dynamic array instead of open:
Code: [Select]
type
  TArr: array of array of Integer;
  procedure Qqq(Arr: TArr);
Lazarus 2.1.0 r61214:62238 FPC 3.3.1 r40507 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

photor

  • New Member
  • *
  • Posts: 49
Re: multi-dimensional open array parameter?
« Reply #2 on: May 31, 2014, 04:20:58 am »
You can use dynamic array instead of open:
Code: [Select]
type
  TArr: array of array of Integer;
  procedure Qqq(Arr: TArr);
So, free pascal doesn't originally support multi-dimensional open arrays, am I right?
I have tried dynamic array, as
Code: [Select]
type
  TArr=array of array of Integer;
var
  ar2:array[0..1,0..1] of Integer=((2,-1),(-3,2));
procedure Qqq(Arr: TArr);
But when I call
Code: [Select]
  Qqq(ar2);in the program, the compiler said
Quote
Error: Incompatible type for arg no. 1: Got "Array[0..1] Of Array[0..1] Of LongInt", expected "TArr"
. Any ideas?

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3647
  • I like bugs.
Re: multi-dimensional open array parameter?
« Reply #3 on: May 31, 2014, 09:37:02 am »
. Any ideas?

The type of ar2 must also be TArr. Pascal is strict with types. It is good idea to always define and use new types for such arrays.

photor

  • New Member
  • *
  • Posts: 49
Re: multi-dimensional open array parameter?
« Reply #4 on: May 31, 2014, 10:22:31 am »
. Any ideas?

The type of ar2 must also be TArr. Pascal is strict with types. It is good idea to always define and use new types for such arrays.
Maybe I haven't expressed myself clearly enough. I want to write a procedure to deal with ar2 (a constant matrix with undetermined size), but I have no idea how to pass ar2 to that procedure as a parameter. Any suggestions?

taazz

  • Hero Member
  • *****
  • Posts: 5363
Re: multi-dimensional open array parameter?
« Reply #5 on: May 31, 2014, 10:39:16 am »
you do something along the lines of
Code: [Select]
type
type
  T2DIntArray = array of array of Integer;

procedure CallOnArray(var anArray:T2DIntArray);
begin

end;

procedure SetLength2D(var anArray:T2DIntArray; Dim1,Dim2:Integer);
var
  vCntr : integer;
begin
  SetLength(anArray,Dim1);
  for vCntr := 0 to Dim1-1 do begin
    SetLength(anArray[vCntr],Dim2);
  end;
end;

procedure Test;
var
  ar2 : T2dIntArray;
begin
  SetLength2D(ar2,2,3);
  callOnArray(ar2);
end;
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

Leledumbo

  • Hero Member
  • *****
  • Posts: 8114
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: multi-dimensional open array parameter?
« Reply #6 on: May 31, 2014, 11:10:47 am »
I suggest using container classes such as list instead of arrays for this. However, I don't think there's something built-in for this. So I end up writing this:
Code: [Select]
{$mode objfpc}{$H+}

uses
  fgl;

type
 
  TIntegerList = class(specialize TFPGList<Integer>)
  private
    function GetIt(Index: Integer): Integer;
    procedure PutIT(Index: Integer; const Item: Integer);
  public
    property Items[i: Integer]: Integer read GetIt write PutIt; default;
  end;
 
  TIntegerMatrix = class(specialize TFPGObjectList<TIntegerList>)
  private
    function GetIt(Index: Integer): TIntegerList;
  public
    constructor Create;
    property Items[i: Integer]: TIntegerList read GetIt; default;
  end;

{ TIntegerList }

function TIntegerList.GetIt(Index: Integer): Integer;
begin
  if Index >= Count then Result := 0 else Result := Get(Index);
end;

procedure TIntegerList.PutIt(Index: Integer; const Item: Integer);
begin
  if Index >= Count then Count := Index + 1;
  Put(Index,Item);
end;

{ TIntegerMatrix }

constructor TIntegerMatrix.Create;
begin
  inherited Create(true);
end;

function TIntegerMatrix.GetIt(Index: Integer): TIntegerList;
var
  OldCount,i: Integer;
begin
  if Index >= Count then begin
    OldCount := Count;
    Count := Index + 1;
    for i := OldCount to Count - 1 do begin
      Put(i,TIntegerList.Create);
    end;
  end;
  Result := Get(Index);
end;

procedure ManipulateIntegerMatrix(m: TIntegerMatrix);
var
  i,j: Integer;
begin
  for i := 0 to m.Count - 1 do
    for j := 0 to m[i].Count - 1 do
      m[i][j] := -m[i][j];
end;

var
  a: TIntegerMatrix;
  i,j: Integer;
begin
  a := TIntegerMatrix.Create;

  a[0][0] := 1; a[0][1] := 2; a[0][2] := 3;
  a[1][0] := 4; a[1][1] := 5; a[1][2] := 6;
  a[2][0] := 7; a[2][1] := 8; a[2][2] := 9;

  WriteLn('Before:');
  for i := 0 to a.Count - 1 do begin
    for j := 0 to a[i].Count - 1 do
      Write(a[i][j]:3);
    WriteLn;
  end;

  ManipulateIntegerMatrix(a);
 
  WriteLn('After:');
  for i := 0 to a.Count - 1 do begin
    for j := 0 to a[i].Count - 1 do
      Write(a[i][j]:3);
    WriteLn;
  end;

  a.Free;
end.
Note that my convention is no error shall be generated for accessing index outside existing ones. Instead, 0 shall be returned for inner index, while new TIntegerList instance will be returned for outer index. It's up to you whether to follow or change this.

photor

  • New Member
  • *
  • Posts: 49
Re: multi-dimensional open array parameter?
« Reply #7 on: May 31, 2014, 12:17:50 pm »
Thanks for all the warm replies. But it is a pity that free pascal doesn't support multi-dimensional open array parameters. To me, extending the function of one-dimensional open array parameters to the multi-dimensional case is not a big challenge to the free pascal developers.

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: multi-dimensional open array parameter?
« Reply #8 on: May 31, 2014, 01:42:42 pm »
Was there something wrong with taazz code? I can give another example
Code: [Select]
type
  TArr = array of array of integer;
...
procedure Test(arr: TArr);
begin
  arr[high(arr), high(arr[0])]:=1;
end;

procedure TForm1.FormCreate(Sender: TObject);
var arr: TArr;
begin
  setlength(arr, 10, 20); // 10x20 matrix
  arr[9, 19]:=0;
  Test(arr);
  caption:=inttostr(arr[9, 19]); // Sets caption 1
end;
In nowhere did i tell Test() function that the matrix size was 10x20, but it could still modify the last value.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8114
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: multi-dimensional open array parameter?
« Reply #9 on: May 31, 2014, 01:43:28 pm »
Thanks for all the warm replies. But it is a pity that free pascal doesn't support multi-dimensional open array parameters. To me, extending the function of one-dimensional open array parameters to the multi-dimensional case is not a big challenge to the free pascal developers.
If you think so, then implement. Welcome to open source world.

photor

  • New Member
  • *
  • Posts: 49
Re: multi-dimensional open array parameter?
« Reply #10 on: May 31, 2014, 02:38:49 pm »
Was there something wrong with taazz code? I can give another example
Code: [Select]
type
  TArr = array of array of integer;
...
procedure Test(arr: TArr);
begin
  arr[high(arr), high(arr[0])]:=1;
end;

procedure TForm1.FormCreate(Sender: TObject);
var arr: TArr;
begin
  setlength(arr, 10, 20); // 10x20 matrix
  arr[9, 19]:=0;
  Test(arr);
  caption:=inttostr(arr[9, 19]); // Sets caption 1
end;
In nowhere did i tell Test() function that the matrix size was 10x20, but it could still modify the last value.
I mean using a CONSTANT matrix, say
Code: [Select]
ar2:array[0..1,0..1] of Integer=((2,-1),(-3,2));as the input of a function.

photor

  • New Member
  • *
  • Posts: 49
Re: multi-dimensional open array parameter?
« Reply #11 on: May 31, 2014, 02:41:54 pm »
Thanks for all the warm replies. But it is a pity that free pascal doesn't support multi-dimensional open array parameters. To me, extending the function of one-dimensional open array parameters to the multi-dimensional case is not a big challenge to the free pascal developers.
If you think so, then implement. Welcome to open source world.
Free pascal is too huge a project for me. I completely don't know where in the source code I can edit.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8114
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: multi-dimensional open array parameter?
« Reply #12 on: May 31, 2014, 03:39:12 pm »
Thanks for all the warm replies. But it is a pity that free pascal doesn't support multi-dimensional open array parameters. To me, extending the function of one-dimensional open array parameters to the multi-dimensional case is not a big challenge to the free pascal developers.
If you think so, then implement. Welcome to open source world.
Free pascal is too huge a project for me. I completely don't know where in the source code I can edit.
Then saying it's not a big challenge is not appropriate. There are implementation details that prevent this from being implemented. Note that open array accepts ANY kind of array, static or dynamic, even partial. So how would you pass a multidimensional static and dynamic array and treat them being equal? Both have different internal representation. A static array, no matter how many dimensions, is still implemented as a flat memory data. Dynamic array, OTOH, when used with >1 dimension is an array of pointers (even as a single dimension, it's internally a pointer). Therefore, it can't be treated as flat memory data because each row is NOT adjacent. It still works for single dimension because the treatment could be equal as flat memory data.

howardpc

  • Hero Member
  • *****
  • Posts: 3197
Re: multi-dimensional open array parameter?
« Reply #13 on: May 31, 2014, 04:41:05 pm »
I mean using a CONSTANT matrix, say
Code: [Select]
ar2:array[0..1,0..1] of Integer=((2,-1),(-3,2));as the input of a function.

This is possible in Pascal using a user-defined type, as Juha pointed out. Such as this:
Code: [Select]
program ConstantMatrix;

type
  T2DArray = array[0..1,0..1] of integer;

const
  Array2D: T2DArray = ((2,-1),(-3,2));

  procedure SqrArray(var anArray: T2DArray);
  var
    i, j: integer;
  begin
    for i:=0 to 1 do
      for j:=0 to 1 do
        anArray[i,j]:=sqr(anArray[i,j]);
  end;

  procedure DisplayArray(anArray: T2DArray; const aTitle:string);
  var
    i, j: integer;
  begin
    WriteLn(aTitle);
    for i:=0 to 1 do begin
      for j:=0 to 1 do
        Write(anArray[i][j]:3);
      WriteLn;
    end;
  end;

var
  ar2:T2DArray;
begin
  ar2:=Array2D;
  DisplayArray(ar2,'Before:');
  SqrArray(ar2);
  DisplayArray(ar2,'After SqrArray():');
  ReadLn;
end.

mse

  • Sr. Member
  • ****
  • Posts: 286
Re: multi-dimensional open array parameter?
« Reply #14 on: May 31, 2014, 05:12:38 pm »
If solely the first dimension is variable it is possible:
Code: [Select]
type
 arty = array[0..1] of integer;
 
procedure test(p: array of arty);
begin
end;

const
 ar2: array[0..1] of arty = ((2,-1),(-3,2));
 
procedure test2();
begin
 test(ar2);
end;

Or use an open type parameter:

Code: [Select]
const
 ar1: array[0..1,0..1] of integer = ((2,-1),(-3,2));

procedure test3(const ar; const high1: integer; const high2: integer);
begin
end;

procedure test4();
begin
 test3(ar1,high(ar1),high(ar1[0]));
end;