Recent

Author Topic: [SOLVED] How can I write a generic procedure?  (Read 557 times)

egsuh

  • Full Member
  • ***
  • Posts: 248
[SOLVED] How can I write a generic procedure?
« on: August 14, 2019, 03:38:15 am »
In practice, I'd like to write a procedure that add new value to the end of a dynamic value.

In case of integer array, I might write the procedure as:

Code: Pascal  [Select]
  1. type
  2.     TMyArr: TArray<integer>;
  3.  
  4. procedure AddValue(var Myarr: TMyArr; NewValue: integer);
  5. begin
  6.      SetLength(MyArr, Length(MyArr) + 1);
  7.      MyArr[High(MyArr)] := NewValue;
  8. end;  
  9.  

Can I write a generic procedure like

procedure AddValue(var arr:TArray<T>; AValue:<T>);

Hope that you understand what  I mean.  I'm aware of the issue of copying or referencing  the contents of the dynamic array. I'll test it myself. Please comment on writing the generic procedure.
« Last Edit: August 15, 2019, 03:02:47 pm by egsuh »

bytebites

  • Full Member
  • ***
  • Posts: 220
Re: How can I write a generic procedure?
« Reply #1 on: August 14, 2019, 05:18:39 am »
Code: Pascal  [Select]
  1. procedure AddValue<T>(var arr:TArray<T>; AValue:T);
  2. begin
  3.      SetLength(arr, Length(arr) + 1);
  4.      arr[High(arr)] := AValue;
  5. end;

Thaddy

  • Hero Member
  • *****
  • Posts: 9293
Re: How can I write a generic procedure?
« Reply #2 on: August 14, 2019, 08:08:02 am »
Note that such code is slow because of the copy semantics of SetLength(). So if you call this often....better use a TList<T> instead of an array. Lists grow more efficient.
Conversion from array to list is easy. Create the list and call TList<T>.AddRange(values:array of T);
Of course don't do that internally... but use lists instead of arrays. Only relevant if you add a lot.
« Last Edit: August 14, 2019, 08:20:25 am by Thaddy »
also related to equus asinus.

PascalDragon

  • Hero Member
  • *****
  • Posts: 735
  • Compiler Developer
Re: How can I write a generic procedure?
« Reply #3 on: August 14, 2019, 09:26:13 am »
Independently of that Thaddy's explanation that lists are more efficient if many items are added is correct: the example provided by bytebites is correct, however it requires FPC 3.2 or newer. You can alternatively put the procedure into a generic record as a class procedure.

And in 3.2 you can also use this:

Code: Pascal  [Select]
  1. var
  2.   arr: TArray<LongInt>;
  3. begin
  4.   arr := [1, 2, 3, 4];
  5.   // both of the following can be used to insert elements at the end
  6.   // Note: in non-Delphi modes modeswitch ArrayOperators is required for the "+" to work
  7.   arr := arr + [5];
  8.   Insert(6, arr, Length(arr));
  9. end.

julkas

  • Sr. Member
  • ****
  • Posts: 437
  • KISS principle / Lazarus 2.0.0 / FPC 3.0.4
Re: How can I write a generic procedure?
« Reply #4 on: August 14, 2019, 12:02:17 pm »
In practice, I'd like to write a procedure that add new value to the end of a dynamic value.
If you want only this - don't reinvent the wheel.
Use standard light TVector from fcl-stl package (C++ STL analog) or advanced TList from here - https://github.com/maciej-izak/generics.collections (clone and add to the project, if you are using FPC 3.0.4), it's Delphi compatible.
« Last Edit: August 14, 2019, 12:10:14 pm by julkas »
procedure mulu64(a, b: QWORD; out clo, chi: QWORD); assembler;
asm
  mov rax, a
  mov rdx, b
  mul rdx
  mov [clo], rax
  mov [chi], rdx
end;

egsuh

  • Full Member
  • ***
  • Posts: 248
Re: How can I write a generic procedure?
« Reply #5 on: August 15, 2019, 03:02:30 pm »
Ah...
There have been many possible solutions already. Each one is quite valuable. 
I appreciate all of your comments.