Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2020-09

Feature request/discussion - SetLengthNoInit

23 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

J. Gareth Moreton

Hi everyone,

This is something that came up in a discussion with a client. One thing he noticed when using SetLength with dynamic arrays is that it can cause a CPU bottleneck because it initialises the entire block to zero, which is often undesirable if the array is going to be overwritten with its own values (in his own example, he's passing the array to a GPU shader as an output buffer).  I mentioned that the best ways around this is to either pre-initialise the array and just reuse it where and when you need it (object pooling) or to use GetMem and FreeMem, which increases the danger of memory leaks, dangling pointers and removes the benefits of a managed type.

With all this in mind, would there be support for an intrinsic such as "SetLengthNoInit" or "SetLengthNoClear" or some similar name that has all the benefits of SetLength (especially the reference counting) but doesn't initialise new elements to zero? If I'm learning one thing, Free Pascal is finding a niche in some scientific applications, and speed can be essential sometimes.

Gareth aka. Kit

This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

Michael Van Canneyt
to J. Gareth Moreton
J. Gareth Moreton wrote 19 lines
Hi everyone, This is something that came up in a discussion with a client. One thing he noticed when using SetLength with dynamic arrays is that it can cause a CPU bottleneck because it initialises the entire block to zero, which is often undesirable if the array is going to be overwritten with its own values (in his own example, he's passing the array to a GPU shader as an output buffer).  I mentioned that the best ways around this is to either pre-initialise the array and just reuse it where and when you need it (object pooling) or to use GetMem and FreeMem, which increases the danger of memory leaks, dangling pointers and removes the benefits of a managed type. With all this in mind, would there be support for an intrinsic such as "SetLengthNoInit" or "SetLengthNoClear" or some similar name that has all the benefits of SetLength (especially the reference counting) but doesn't initialise new elements to zero? If I'm learning one thing, Free Pascal is finding a niche in some scientific applications, and speed can be essential sometimes.
Better add an additional (optional) parameter SkipInit : Boolean = False;

Michael.

Reply by email

J. Gareth Moreton
to Michael Van Canneyt
Michael Van Canneyt wrote
Better add an additional (optional) parameter SkipInit : Boolean = False; Michael.

That won't work because constructs such as "var Data: array of array of Byte; SetLength(Data, 25, 25);" are allowed.  Eevn if it's technically an intrinsic and the compiler can have customised handling, I think it will cause too much confusion to have an optional Boolean parameter like that.  Also, it might cause unnecessary additional overhead since it wastes a register to pass the Boolean value that, in most cases, is equal to False (implicitly or otherwise).

Finally, the fact it's a parameter implies that you can use a (non-deterministic) variable as an actual parameter, which is logically something that should never have a practical application in this case; i.e. why should initialising the data to zeroes be undecided at run-time? Surely you, the programmer, know what you're going to do with that data block.

I understand there's a risk of it breaking existing code should a unit have a subroutine with the name "SetLengthNoInit", although long names with multiple words reduces this risk, and if there is a clash, doesn't the compiler prioritise the subroutine defined in the unit? Should you want to use the internal "SetLengthNoInit" in this case, you will need to call "System.SetLengthNoInit", right?

Gareth aka. Kit

This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

J. Gareth Moreton
to J. Gareth Moreton
Michael Van Canneyt wrote
> Better add an additional (optional) parameter SkipInit : Boolean = > False; > > Michael.

I was probably a bit too critical in my last e-mail.  I'm sure it's possible given SetLength is an intrinsic rather than a real subroutine.  Is it possible to add an extra parameter and have the compiler detect whether it is for setting a length or specifying "no initialisation"?  I'm just a tad concerned about avoiding additional overhead should the parameter be omitted and the effect of explicitly specifying False (since the actual parameter could be a Boolean variable and the internal "set_length_no_init" routine will then require an extra check to see if this parameter actually is set to True in order to ensure correct behaviour).

Gareth aka. Kit

This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

Michael Van Canneyt
to J. Gareth Moreton: That won't work because constructs such as "var Data: array of array of Byte;…
J. Gareth Moreton wrote 10 lines
On 14/09/2020 19:41, Michael Van Canneyt via fpc-devel wrote: > Better add an additional (optional) parameter SkipInit : Boolean = False; > > Michael. That won't work because constructs such as "var Data: array of array of Byte; SetLength(Data, 25, 25);" are allowed.? Eevn if it's technically an intrinsic and the compiler can have customised handling, I think it will cause too much confusion to have an optional Boolean parameter like that.?

I think adding even more intrinsics to the compiler is really not an option. The system unit is already overcrowded and bloated with intrinsics, so adding even more for what is at best a real corner case: I really don't think that's a good idea.

If speed matters so much to some people, don't use setlength(), use getmem().

Michael.

Reply by email

Sven Barth
to J. Gareth Moreton: This is something that came up in a discussion with a client. One thing he noticed when…

J. Gareth Moreton via fpc-devel schrieb am
Mo., 14. Sep. 2020, 19:00:

Show quoted text 7 lines
With all this in mind, would there be support for an intrinsic such as "SetLengthNoInit" or "SetLengthNoClear" or some similar name that has all the benefits of SetLength (especially the reference counting) but doesn't initialise new elements to zero? If I'm learning one thing, Free Pascal is finding a niche in some scientific applications, and speed can be essential sometimes.

I'm against adding support for this. Dynamic arrays have guaranteed behavior. If users find that this behavior is not appropriate for their use case then they should not use them (or as you already suggested, preallocate them).

Regards,
Sven

Reply by email

RORDEN, CHRIS

The dynamic arrays in Lazarus have so many terrific properties. Giving power users the ability to not initialize them would give clear performance benefits. This is useful in real world sitautions where one has long term arrays, but also can use transient arrays of the same type. Another feature that could help power users is the ability to set the alignment of setlength() - see issue 0034031. From my view, dynamic arrays are one of the features that makes Pascal code so much nicer than C. Web searches for "Speed "problem" with SetLength” and "Faster way of initializing arrays in Delphi” suggest others encounter these issues as well. I would advocate for a couple of advanced and optional features (alignment and initialization control) would allow this elegant property of Pascal to scale into these niches. It certainly makes code moree readable and consistent to keep one type of structure, rather than having to switch to GetMem for doing some tasks (SIMD, GPU, transient large arrays). Giving users control can obviously deviate from guaranteed behavior (e.g. one could choose a poor alignment, or not initialize strong arrays and leave random data in elements). However, allowing advanced users to elect to use these features would really help dynamic arrays scale to problems we face in the real world.

Despite these preferences, the experiment below shows that even for very large arrays, the initialization penalty may not be big so long as long you fill the array immediately after setting the length of the array. Note that SetLength() is very slow, but the subsequent filling of the array is fast (presumably due to cache), while getmem returns quickly, but the intiailization is substantially slower. I would be grateful if anyone can suggest any issues here or any method to accelerate either set of routines.

Milliseconds SetLength: 214..221 mean 218
Milliseconds fill array: 56..103 mean 95
Milliseconds GetMem: 0..0 mean 0
Milliseconds fill array: 251..270 mean 259

--------------------

program test3;
//fpc -O3 test3.pas; ./test3
{$IFDEF FPC}{$mode delphi} {$H+}{$ENDIF}
  uses Math, SysUtils,DateUtils;
type
 TUInt32s = array of uint32;
 TInt32s = array of int32;
 TRGBA = packed record //red,green,blue,alpha
   R,G,B,A : byte;
 end;
 TRGBAs = array of TRGBA;
 TRGBA0 = array [0..MAXINT] of TRGBA;
 TRGBAp = ^TRGBA0; //pointer to RGBA array
 TUInt320 = array [0..MAXINT] of uint32;
 TUInt32p = ^TUInt320; //pointer to RGBA array
procedure SetLengthP(var S: TRGBAp; Len: SizeInt); overload;
begin
ReAllocMem(S, Len *sizeof(TRGBA));
end;
procedure setlengthTest();
const
nVox = (512 * 512 * 512); //typical CT scan as RGBA array
nTest = 10;
var
startTime: TDateTime;
i, j, ms, mn,mx,tot, mn2, mx2, tot2: int64;
ArrayDyn: TRGBAs;
Arrayp: TRGBAp;
asUint32s: TUInt32s;
asUint32p: TUInt32p;
begin
//setlength() is slow, presumably because it intializes array (fillchar())
//https://alt.comp.lang.borland-delphi.narkive.com/O0jRrNgS/speed-problem-with-setlength
//test setlength
mn := maxint;
mx := 0;
tot :=  0;
mn2 := maxint;
mx2 := 0;
tot2 :=  0;
for i := 1 to nTest do begin
startTime := Now;
SetLength(ArrayDyn, nVox);
ms := MilliSecondsBetween(Now,startTime);
mn := min(ms,mn);
mx := max(ms,mx);
tot += ms;
//fill arrays
startTime := Now;
asUint32s := TUInt32s(ArrayDyn);
for j := 0 to nVox-1 do
asUint32s[j] := (j );
SetLength(ArrayDyn,0);
ms := MilliSecondsBetween(Now,startTime);
mn2 := min(ms,mn2);
mx2 := max(ms,mx2);
tot2 += ms;
end;
writeln(format('Milliseconds SetLength: %d..%d mean %d', [mn,mx, round(tot/nTest)]));
writeln(format('Milliseconds fill array: %d..%d mean %d', [mn2,mx2, round(tot2/nTest)]));
//test GetMem
mn := maxint;
mx := 0;
tot :=  0;
mn2 := maxint;
mx2 := 0;
tot2 :=  0;
Arrayp := nil; //must initialize!
for i := 1 to nTest do begin
startTime := Now;
SetLengthP(Arrayp, nVox);
ms := MilliSecondsBetween(Now,startTime);
mn := min(ms,mn);
mx := max(ms,mx);
tot += ms;
//fill arrays
startTime := Now;
{$IFDEF X}
asUint32s := TUInt32s(Arrayp);
for j := 0 to nVox-1 do
asUint32s[j] := (j );
{$ELSE}
asUint32p := TUInt32p(Arrayp);
for j := 0 to nVox-1 do
asUint32p[j] := (j );
{$ENDIF}
SetLengthP(Arrayp,0);
ms := MilliSecondsBetween(Now,startTime);
mn2 := min(ms,mn2);
mx2 := max(ms,mx2);
tot2 += ms;
end;
writeln(format('Milliseconds GetMem: %d..%d mean %d', [mn,mx, round(tot/nTest)]));
writeln(format('Milliseconds fill array: %d..%d mean %d', [mn2,mx2, round(tot2/nTest)]));
end;
begin
setlengthTest();
    Exit;
end.

Reply by email

J. Gareth Moreton
to Sven Barth: J. Gareth Moreton via fpc-devel schrieb am Mo., 14. Sep. 2020, 19:00: I'm against adding…

You all make good points.  It's why I didn't suggest changing SetLength because of the well-defined and safe behaviour, and yes, the System unit is already crowded with intrinsics, and will become even more crowded once the naming format of the assembly intrinsics are finalised.  The optional parameter (or a new intrinsic) wouldn't change anything that already exists, and can be documented.

I'm willing to settle with SetLength(array, len, ... len, NoInit: Boolean = False), but of course it depends on the overall support for it, which isn't looking too promising currently!

Gareth aka. Kit

Sven Barth wrote 23 lines
J. Gareth Moreton via fpc-devel < > schrieb am Mo., 14. Sep. 2020, 19:00: With all this in mind, would there be support for an intrinsic such as "SetLengthNoInit" or "SetLengthNoClear" or some similar name that has all the benefits of SetLength (especially the reference counting) but doesn't initialise new elements to zero? If I'm learning one thing, Free Pascal is finding a niche in some scientific applications, and speed can be essential sometimes. I'm against adding support for this. Dynamic arrays have guaranteed behavior. If users find that this behavior is not appropriate for their use case then they should not use them (or as you already suggested, preallocate them). Regards, Sven
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

RORDEN, CHRIS

I think dynamic arrays are really elegant features of Pascal and a strong benefit versus C. However, when working with large projects one encounters situations where one wants more. control. I would advocate allowing developers to optionally use SetLengthNoInit and also allowing user to specify the alignment of dynamic arrays - see issue 0034031. In real world large projects, one encounters situtations where both features are useful. While one could use GetMem for these features, it makes the code less maintainable when some use cases are ideal for dynamic arrays and others for GetMem. These tiny changes would not impact normal users, but allow power users to use this one elegant design for a wide array of use cases. Web searches for "Speed "problem" with SetLength” and "Faster way of initializing arrays in Delphi” suggest others encounter these issues as well.

Reply by email

Ryan Joseph
to J. Gareth Moreton: You all make good points.  It's why I didn't suggest changing SetLength because of the…
Show quoted text 5 lines
On Sep 15, 2020, at 10:34 PM, J. Gareth Moreton via fpc-devel wrote: I'm willing to settle with SetLength(array, len, ... len, NoInit: Boolean = False), but of course it depends on the overall support for it, which isn't looking too promising currently!

I'd rather put the time into making custom list classes perform as well as dynamic arrays. I liked the idea that FPC has it's own native "array of" syntax but it's tied to the language and not flexible enough as we learn from time to time.

Two biggest things I can think of right away:

1) We have management operators now for ref counting but the code is probably not as good as with dynamic arrays (the operator calls are not inlined I know). Also I was never able to get my patch for a Move operator added and I regard this as pretty important to avoid unnecessary copies.

2) I think for the [] operator to work with arrays of records you need to return pointers and enable the "autoderef" modeswitch to avoid the deref syntax (which is how dynamic arrays always work). Are there performance implications of this or do we get the same code as dynamic arrays?

Regards,
Ryan Joseph

Reply by email

Benito van der Zander
to Sven Barth: J. Gareth Moreton via fpc-devel schrieb am Mo., 14. Sep. 2020, 19:00: I'm against adding…

Hi,

Show quoted text 5 lines
I'm against adding support for this. Dynamic arrays have guaranteed behavior. If users find that this behavior is not appropriate for their use case then they should not use them (or as you already suggested, preallocate them).

well, setlength does not always initialize the array

That is why the new fpc versions always show a "might be uninitialized"-warning, when setlength is called without setting the array to nil first

Bye,
Benito

Sven Barth wrote 28 lines
J. Gareth Moreton via fpc-devel < > schrieb am Mo., 14. Sep. 2020, 19:00: With all this in mind, would there be support for an intrinsic such as "SetLengthNoInit" or "SetLengthNoClear" or some similar name that has all the benefits of SetLength (especially the reference counting) but doesn't initialise new elements to zero? If I'm learning one thing, Free Pascal is finding a niche in some scientific applications, and speed can be essential sometimes. I'm against adding support for this. Dynamic arrays have guaranteed behavior. If users find that this behavior is not appropriate for their use case then they should not use them (or as you already suggested, preallocate them). Regards, Sven _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

J. Gareth Moreton
to Ryan Joseph: I'd rather put the time into making custom list classes perform as well as dynamic…

I did wonder if it was possible to use an object of some kind or, I dare say, some evil low-level manipulation of its internal structure wrapped into a convenient function that, say, calls ReallocMem on the internal pointer and sets the length field as normal.  The trouble is, that will be inherently unsafe on account that you can't pass an untyped dynamic array as a formal parameter ("array of const" is, as the name implies, an array of constants that's just a list).

I figure I could design a dynamic array class, but it will very likely be incompatible with SetLength no matter what I try to do, and unless I'm mistaken, it won't have the benefit of automatically gaining an implicit clean-up blocl if used as a local variable unless there's an automatic reference counting feature that I'm not aware of.

Gareth aka. Kit

Ryan Joseph wrote 22 lines
> On Sep 15, 2020, at 10:34 PM, J. Gareth Moreton via fpc-devel wrote: > > I'm willing to settle with SetLength(array, len, ... len, NoInit: Boolean = False), but of course it depends on the overall support for it, which isn't looking too promising currently! > > I'd rather put the time into making custom list classes perform as well as dynamic arrays. I liked the idea that FPC has it's own native "array of" syntax but it's tied to the language and not flexible enough as we learn from time to time. Two biggest things I can think of right away: 1) We have management operators now for ref counting but the code is probably not as good as with dynamic arrays (the operator calls are not inlined I know). Also I was never able to get my patch for a Move operator added and I regard this as pretty important to avoid unnecessary copies. 2) I think for the [] operator to work with arrays of records you need to return pointers and enable the "autoderef" modeswitch to avoid the deref syntax (which is how dynamic arrays always work). Are there performance implications of this or do we get the same code as dynamic arrays? Regards, Ryan Joseph _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

Michael Van Canneyt
to Benito van der Zander: well, setlength does not always initialize the array That is why the new fpc versions…
Benito van der Zander wrote 10 lines
Hi, > > I'm against adding support for this. Dynamic arrays have guaranteed > behavior. If users find that this behavior is not appropriate for their use > case then they should not use them (or as you already suggested, > preallocate them). well, setlength does not always initialize the array

Of course it does.

That is why the new fpc versions always show a "might be uninitialized"-warning, when setlength is called without setting the array to nil first

That is because you pass it an uninitialized array, not because SetLength() possibly would not do something.

Michael.

Reply by email

Sven Barth
to J. Gareth Moreton: I did wonder if it was possible to use an object of some kind or, I dare say, some evil…

J. Gareth Moreton via fpc-devel schrieb am
Mi., 16. Sep. 2020, 16:10:

Show quoted text 8 lines
I did wonder if it was possible to use an object of some kind or, I dare say, some evil low-level manipulation of its internal structure wrapped into a convenient function that, say, calls ReallocMem on the internal pointer and sets the length field as normal. The trouble is, that will be inherently unsafe on account that you can't pass an untyped dynamic array as a formal parameter ("array of const" is, as the name implies, an array of constants that's just a list).

"array of const" is internally an "array of TVarRec" and can be used for non constants as well (there values will be copied to the open array).

Regards,
Sven

Reply by email

Sven Barth
to Benito van der Zander: well, setlength does not always initialize the array That is why the new fpc versions…

Benito van der Zander via fpc-devel
schrieb am Mi., 16. Sep. 2020, 15:30:

Show quoted text 15 lines
Hi, I'm against adding support for this. Dynamic arrays have guaranteed behavior. If users find that this behavior is not appropriate for their use case then they should not use them (or as you already suggested, preallocate them). well, setlength does not always initialize the array That is why the new fpc versions always show a "might be uninitialized"-warning, when setlength is called without setting the array to nil first

Then you have not understood what the warning is for. If you cal SetLength FPC will always initialize the new memory area that is added. However if you use SetLength on a Result variable then this array might already be initialized. So if the Result variable should have 5 elements upon function entry and you set the length of the array to 2 then the first two entries will retain their value. If you set it to 7 instead then the first 5 entries will be kept and the new two will be initialized. The RTL behaves here as described: it always initializes new parts of the array.

Regards,
Sven

Reply by email

Ryan Joseph
to J. Gareth Moreton: I did wonder if it was possible to use an object of some kind or, I dare say, some evil…
On Sep 16, 2020, at 9:10 PM, J. Gareth Moreton via fpc-devel wrote: I figure I could design a dynamic array class, but it will very likely be incompatible with SetLength no matter what I try to do, and unless I'm mistaken, it won't have the benefit of automatically gaining an implicit clean-up blocl if used as a local variable unless there's an automatic reference counting feature that I'm not aware of.

There are operators to do this now but they're only for records (https://wiki.freepascal.org/management_operators). You can easily make a reference counted type now but as I mentioned that are some drawbacks, some of which I'd like to correct if the compiler team allowed it.

Regards,
Ryan Joseph

Reply by email

J. Gareth Moreton
to Ryan Joseph

I hope they do allow you to fix it, because those features look useful, especially with custom-made dynamic arrays (through a generic record).  I've got to try playing with them now to see if I can make something that Chris Rorden would use!

Though not really related, it's not easy to specify a pointer to a type parameter in a generic type.  For example, if I try to declare:

type generic TMyArray<T> = record
   Data: ^T;
   Length: PtrUInt;
end;

The compiler will complain about T being an unresolved forward declaration.  Outside of specifying a second parameter for the pointer type (which would be a little unfriendly for third-party users), there isn't really a way around this.

Gareth aka. Kit

Ryan Joseph wrote 13 lines
> On Sep 16, 2020, at 9:10 PM, J. Gareth Moreton via fpc-devel wrote: > > I figure I could design a dynamic array class, but it will very likely be incompatible with SetLength no matter what I try to do, and unless I'm mistaken, it won't have the benefit of automatically gaining an implicit clean-up blocl if used as a local variable unless there's an automatic reference counting feature that I'm not aware of. There are operators to do this now but they're only for records (https://wiki.freepascal.org/management_operators). You can easily make a reference counted type now but as I mentioned that are some drawbacks, some of which I'd like to correct if the compiler team allowed it. Regards, Ryan Joseph _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

Ryan Joseph
to J. Gareth Moreton
Show quoted text 9 lines
On Sep 17, 2020, at 9:59 AM, J. Gareth Moreton via fpc-devel wrote: type generic TMyArray<T> = record Data: ^T; Length: PtrUInt; end; The compiler will complain about T being an unresolved forward declaration. Outside of specifying a second parameter for the pointer type (which would be a little unfriendly for third-party users), there isn't really a way around this.

To be clear all the features work but it's not as optimized as dynamic arrays and could be cumbersome with arrays of records.

I think you're supposed to redeclare a pointer to T:

type generic TMyArray<T> = record
  type
    TP = ^T;
  public
    Data: TP;
    Length: PtrUInt;
end;

Regards,
Ryan Joseph

Reply by email

Ryan Joseph
to J. Gareth Moreton: I hope they do allow you to fix it, because those features look useful, especially with…

Here's an example of the main problem that keeps us from using custom types to replace dynamic arrays. We basically a need [] property modifier that treats records the same way the dynamic array syntax does. GetValue could be a procedure and use a var parameter and maybe even that would be enough. I don't know what the solutions could be but if the compiler team actually agreed to approve anything I would be happy to personally implement this myself.

============================

{$mode objfpc}
{$modeswitch autoderef}
{$modeswitch advancedrecords}
program dyanmic_array;
type
  TMyRec = record
    x, y: byte;
  end;
type
  generic TArray<T> = record
    private type
      PT = ^T;
    private
      data: array[0..1] of T;
      function GetValue(index: integer): PT; inline;
      procedure SetValue(index: integer; const value: PT); inline;
    public
      property Values[index: integer]: PT read GetValue write SetValue; default;
  end;
  TMyRecArray = specialize TArray<TMyRec>;
function TArray.GetValue(index: integer): PT;
begin
  result := @data[index];
end;
procedure TArray.SetValue(index: integer; const value: PT);
begin
  data[index] := value^;
end;
var
  r: TMyRec;
  a: TMyRecArray;
begin
  r.x := 1;
  r.y := 2;
  // WRONG: we need to use pointers to write to the array
  a[0] := @r;
  // CORRECT: we return pointers to the record so we can write to the underlying data (autoderef must be enabled)
  a[0].x := 100;
  // CORRET: same as above but with member access and autoderef
  writeln('x: ', a[0].x);
  // WRONG: to copy the record out of the array we need to derefence the pointer
  r := a[0]^;
  writeln('r.x: ', r.x);
end.

Regards,
Ryan Joseph

Reply by email

J. Gareth Moreton
to Ryan Joseph: To be clear all the features work but it's not as optimized as dynamic arrays and could…

Ah yes, that works, thanks.

I feel a bit silly because I haven't explored these useful features as much as I should, possibly because assembly language isn't object oriented!

I think the difficulty with getting things like this approved is that it crosses into the realm of defining the language itself.  I can't say I speak on behalf of Florian or Jonas, but I sense they want to avoid feature bloat that became a bit of an issue with Delphi.

Gareth aka. Kit

Ryan Joseph wrote 30 lines
> On Sep 17, 2020, at 9:59 AM, J. Gareth Moreton via fpc-devel wrote: > > type generic TMyArray<T> = record > Data: ^T; > Length: PtrUInt; > end; > > The compiler will complain about T being an unresolved forward declaration. Outside of specifying a second parameter for the pointer type (which would be a little unfriendly for third-party users), there isn't really a way around this. > To be clear all the features work but it's not as optimized as dynamic arrays and could be cumbersome with arrays of records. I think you're supposed to redeclare a pointer to T: type generic TMyArray<T> = record type TP = ^T; public Data: TP; Length: PtrUInt; end; Regards, Ryan Joseph _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

Ozz Nixon
to J. Gareth Moreton

Then, I would suggest it gets bolted into strutils, or sysutils. There are many good reasons to optimize Setlength(), especially for script authors :-)

Currently, I am working (learning) Alpha Controls (alphaskins), and trying to find a fit into FCL/LCL, or Graeme's GUI. And if I tweak too much, things forget to draw - so I understand avoiding "core" bloat. But, Isn't that what SYSUTILs is for :-)

Ozz

On Wed, Sep 16, 2020 at 11:33 PM J. Gareth Moreton via fpc-devel <

Show quoted text 59 lines
wrote: Ah yes, that works, thanks. I feel a bit silly because I haven't explored these useful features as much as I should, possibly because assembly language isn't object oriented! I think the difficulty with getting things like this approved is that it crosses into the realm of defining the language itself. I can't say I speak on behalf of Florian or Jonas, but I sense they want to avoid feature bloat that became a bit of an issue with Delphi. Gareth aka. Kit On 17/09/2020 04:03, Ryan Joseph via fpc-devel wrote: > >> On Sep 17, 2020, at 9:59 AM, J. Gareth Moreton via fpc-devel < > wrote: >> >> type generic TMyArray<T> = record >> Data: ^T; >> Length: PtrUInt; >> end; >> >> The compiler will complain about T being an unresolved forward declaration. Outside of specifying a second parameter for the pointer type (which would be a little unfriendly for third-party users), there isn't really a way around this. >> > To be clear all the features work but it's not as optimized as dynamic arrays and could be cumbersome with arrays of records. > > I think you're supposed to redeclare a pointer to T: > > type generic TMyArray<T> = record > type > TP = ^T; > public > Data: TP; > Length: PtrUInt; > end; > > > Regards, > Ryan Joseph > > _______________________________________________ > fpc-devel maillist - > https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel > -- This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Ryan Joseph
to J. Gareth Moreton: Ah yes, that works, thanks. I feel a bit silly because I haven't explored these useful…
On Sep 17, 2020, at 11:33 AM, J. Gareth Moreton via fpc-devel wrote: I think the difficulty with getting things like this approved is that it crosses into the realm of defining the language itself. I can't say I speak on behalf of Florian or Jonas, but I sense they want to avoid feature bloat that became a bit of an issue with Delphi.

Certainly. I think it depends on what the solution is. It's a known short coming of the [] property and if the solution is as easy as allowing a var param variant then maybe it's feasible.

Regards,
Ryan Joseph

Reply by email

Ryan Joseph
to Ryan Joseph
On Sep 17, 2020, at 7:23 PM, Ryan Joseph wrote: Certainly. I think it depends on what the solution is. It's a known short coming of the [] property and if the solution is as easy as allowing a var param variant then maybe it's feasible.

I'm remembering now I believe we did discuss this and it falls into the category of "not as expected" behavior because it appears like the [] property to write to record fields should work, because the language already gave you that idea from normal static/dynamic arrays. I may have even asked why it didn't work on the mail list and was reminded that it's a feature of the getter method which copies the record as it passes it back. That's not obvious to the programmer unless you really think about how the property is implemented under the hood by the compile.

It would be more intuitive is the record was passed by reference, just like it is using normal [] operators on arrays.

Regards,
Ryan Joseph

Reply by email