[fpc-devel] Managed Types, Undefined Bhaviour

Willibald Krenn Willibald.Krenn at gmx.at
Sat Jun 30 12:02:03 CEST 2018


>Gesendet: Samstag, 30. Juni 2018 um 10:54 Uhr
>Von: "Michael Van Canneyt" <michael at freepascal.org>
>> Am 30.06.2018 um 08:47 schrieb Sven Barth via fpc-devel:
>>> The variables we're talking about here *are* initialized.
>

Bit lost here. Maybe A and B are setup, but not result. And the apparent re-use of tmp vars also seems wrong. In the first call you get a "setup" var, in the second call an "initialized" one with previous values. But the latter is not commonly referred to as initialization, as initialization means usually setting to a sensible default value, which always is the same.

>> Maybe the term initialized is wrong and confusing. They are not initialized
>> in the sense of having defined values as
>> global variables have. Non-global managed types should not be considered as
>> being initialized (never!, like any other
>> type), this is also why the compiler warns (!) about this. They can be
>> considered as being "setup" by the compiler.

So what does setup do - allocate memory and set refcount accordingly? If result was being setup properly that might also help. 

>>> They contain valid values and none of the internal RTL
>>> routines will crash when used with them. Everyone however expects result
>> variables of those to be initialized to Nil and
>>> that is simply *not* a guaranteed given.

I'd say if everyone expects that then there is a point in that the current behaviour is surprising and not intuitive. I mean, the compiler is for people, right? ;) 

>>> Also records only initialize their managed fields. All others are left as
>> garbage.
>>

I'm only talking about managed types.

>
>> Managed fields of records are "setup" ;)
>
>I will add a section about this in the documentation, seeing that people
>often confuse the 2 concepts.


In an ideal world, either the language would not let you write code that has random behavior or the compiler would enforce this.

Out of curiosity I did a couple of more tests and it seems FPC is pretty inconsistent in handling all this. See below.

//... some form in lazarus with a tmemo and a button on it

  TCArray = array of integer;
  TMRecord = record
    arr: TCArray;
  end;

// global vars
var
  A, B: TCArray;
  C, D: TMRecord;

function X(l:integer): TCArray;
begin
  setlength(result,l);
end;

function Y(l: integer): TMRecord;
begin
  setlength(result.arr, l);
end;

procedure global(memo1: TMemo);
begin
  A:=X(3);
  A[0] := 5;
  A[1] := 4;
  B:=X(3);
  // the following will print 5 twice
  memo1.lines.add('GlobalA0: %d',[A[0]]);
  memo1.lines.add('GlobalB0: %d',[B[0]]);

  C := Y(3);
  C.arr[0] := 5;
  C.arr[1] := 4;
  D := Y(3);
  // the following will print 5 and 0
  memo1.lines.add('GlobalC0: %d',[C.arr[0]]);
  memo1.lines.add('GlobalD0: %d',[D.arr[0]]);
end;

{ TForm1 }

// will add the following lines to memo1:
//GlobalA0: 5
//GlobalB0: 5 (this is the strange case...)
//GlobalC0: 5
//GlobalD0: 0
//LocalA0: 5
//LocalB0: 0
//LocalC0: 5
//LocalD0: 0
procedure TForm1.ToggleBox1Change(Sender: TObject);
var
  A, B: TCArray;
  C, D: TMRecord;
begin
  global(memo1);
  A:=X(3);
  A[0] := 5;
  A[1] := 4;
  B:=X(3);
  // the following will print 5 and 0
  memo1.lines.add('LocalA0: %d',[A[0]]);
  memo1.lines.add('LocalB0: %d',[B[0]]);


  C := Y(3);
  C.arr[0] := 5;
  C.arr[1] := 4;
  D := Y(3);
  // the following will print 5 and 0
  memo1.lines.add('LocalC0: %d',[C.arr[0]]);
  memo1.lines.add('LocalD0: %d',[D.arr[0]]);
end;


... And at least with my current settings in Lazarus (standard ones) I don't see any warning about me venturing into the fields of undefined - or - random. 


Best,
 Willibald



More information about the fpc-devel mailing list