Recent

Author Topic: with statement and changed arrays  (Read 4448 times)

BeniBela

  • Hero Member
  • *****
  • Posts: 959
    • homepage
with statement and changed arrays
« on: August 16, 2012, 06:43:08 pm »
It seems you can use with to access array elements,  if the array is changed within the with like this in all optimization levels:
Code: [Select]
var test: array of TRect;
begin
  setlength(test,1);
  with test[0] do begin
    Left:=123;
    setlength(test, 10);
    Left:=456;
  end;

Both assignments to Left change the respective test[0].Left, even if the @test[0] in the first assignment is different to @test[0] in the second assignment.

Is it safe to do this, or do you expect that it will break in future fpc releases?

eny

  • Hero Member
  • *****
  • Posts: 1665
Re: with statement and changed arrays
« Reply #1 on: August 16, 2012, 07:59:25 pm »
Interesting code but this is pushing your luck.
Look for example at this fragment (a recipe for disaster):
Code: Pascal  [Select][+][-]
  1. type PRect = ^TRect;
  2. var  prec: PRect;
  3. begin
  4.   new(prec);
  5.   with prec^ do
  6.   begin
  7.     left := 10;
  8.     dispose(prec);
  9.     left := 20;
  10.   end;
  11. end;
A pointer variable is allocated, used, disposed and after disposal used again.
Better stay away from such constructs.
All posts based on: Win11; stable Lazarus 4_4  (x64) 2026-02-12 (unless specified otherwise...)

ludob

  • Hero Member
  • *****
  • Posts: 1173
Re: with statement and changed arrays
« Reply #2 on: August 16, 2012, 08:13:24 pm »
I think you are playing with fire. It works because the compiler optimisation isn't very good in this case and the address of test[0] is re-calculated every time it is used. I don't think this is the optimiser being smart because when you remove the setlength(test, 10) line, the test[0] is still recalculated to store 456.

http://www.freepascal.org/docs-html/ref/refsu53.html#x145-15500013.2.8 says literally
Quote
Remark: When using a With statement with a pointer, or a class, it is not permitted to change the pointer or the class in the With block.
test[0] is a pointer.

I compiled the same snippet with Delphi 2006 and there test[0] is kept in a register which is not updated after the call to DynArraySetLength. So when DynArraySetLength moves you get there the problems you feared. FPC is not Delphi but it means that the next time there is some improvement made in the FPC compiler optimisation you could end up with SIGSEGV's.  In any case I would recommend to not use this construct, especially since there is no optimisation at all.

Contrary to Knipfty I find that the use of With makes the code more difficult to read especially when using record members such as Left which happen to be also a property of a Form. It adds a lot of ambiguity. Also the debugger can not always find the variable you are referring to.

Knipfty

  • Full Member
  • ***
  • Posts: 232
Re: with statement and changed arrays
« Reply #3 on: August 16, 2012, 08:20:11 pm »
I didn't catch the second setlength in the code.  I was simply answering about the use of a with with arrary of record type.  That said, I would never change the root of the with (pointer, setlength, etc) within the with it self.

And yes, it can get you into trouble whith Left's and Name's, and visible and such.  So you need to be careful.  However, when you are creating your own record types which in many cases will have unique names, I see no issue with using with statements.

The choice is yours...
64-bit Lazarus 2.2.0 FPC 3.2.2, 64-bit Win 11

eny

  • Hero Member
  • *****
  • Posts: 1665
Re: with statement and changed arrays
« Reply #4 on: August 16, 2012, 08:30:47 pm »
Contrary to Knipfty I find that the use of With makes the code more difficult to read especially when using record members such as Left which happen to be also a property of a Form. It adds a lot of ambiguity. Also the debugger can not always find the variable you are referring to.
This is sometimes true, especially for generics.

It can be useful in cases like this:
Code: Pascal  [Select][+][-]
  1. with TMyNiftyDialog.Create(nil) do
  2. begin
  3.   if ShowModal = mrOK then {..} ;
  4.   free
  5. end;
  6.  
All posts based on: Win11; stable Lazarus 4_4  (x64) 2026-02-12 (unless specified otherwise...)

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: with statement and changed arrays
« Reply #5 on: August 17, 2012, 01:24:54 pm »
That is definitely not ok. I can give another example that is also bad:
Code: [Select]
TMyRecord = record
  intVar: integer;
end;

var
  arr: array of TMyRecord;
  count: integer;

function AddElement: integer;
begin
  result:=Count;
  inc(Count);
  setlength(arr, Count);
end;

...
var n: integer;
begin
  with arr[AddElement] do begin
    intVar:=1; // Error!
  end;

  // Do it like this
  n:=AddElement;
  with arr[n] do begin
    intVar:=1; // Ok
  end;
end;

BeniBela

  • Hero Member
  • *****
  • Posts: 959
    • homepage
Re: with statement and changed arrays
« Reply #6 on: August 18, 2012, 05:54:24 pm »
A pity.

It  worked so well...).

Perhaps I change it to a class

 

TinyPortal © 2005-2018