views:

145

answers:

4

Delphi 2010 How to modify TList < record > value ?

type TTest = record a,b,c:Integer end;
var List:TList<TTest>;
    A:TTest;
    P:Pointer;
....
....

List[10] := A;  <- OK
List[10].a:=1;  <- Here compiler error : Left side cannot be assined to
P:=@List[10];   <- Error: Variable requied
+3  A: 
A := List[10];
A.a := 1;
list[10] := A;

You don't have to do this with objects because they're reference types, (accessed through a pointer which the compiler manages internally to keep it out of your hair,) but records are value types so it doesn't work that way.

Mason Wheeler
A: 

Ok, i solved this problem this way:

  type TTest = record a,b,c:Integer end;
       PTest = ^TTest;
  var List:TList<PTest>;
      A:TTest;
  ....
  ....
  List := TList<PTest>.Create;
  List.Add(@A);
  List[0].a:=1;
Astronavigator
IMHO a bad solution... - have a look at the memory management.
Uwe Raabe
You haven't thought this through. What will you do when you want to add a second item to the list? You can't `Add(@A)` again or you'll have aliasing problems. Declare another global variable `B`? If you need to have a separate variable declared for each item in the list, then you may as well ditch the list and use an ordinary array. And if you're going to allocate new records on the heap with `New`, then you introduce memory-management responsibilities that are better solved by using a `TObjectList`. For the sake of one syntax convenience, you add several inconveniences for a net loss.
Rob Kennedy
**Don't to this unless you really like to shoot yourself in the foot**
François
to Rob Kennedy: TObjectList requires for list items to be an object. So you'd prefered to replace type TTest=record a,b,c: integer end; by type TTest = class a,b,c: integer end; and use constructor create instead of new() procedure ? I think this solution will use a lot of memmory with no need to. So if list is big i think its better to use simple base types, not classes.
Astronavigator
@Astronavigator : in your example : A is a local variable, so storing @A in a List is close to suicide if you want to return List as a result of your function. You would need to do "List.Add( AllocMem(SizeOf(TTest)) )", which would be close to creating an object.
LeGEC
Yes, Astronavigator, I would **absolutely** replace the "record+New" solution with a TObject solution. A class takes up only four more bytes than its record equivalent. If that little bit makes a big difference to your program, then if I were you, I wouldn't be worrying about such an inconsequential thing as the syntax for assigning values to members of record properties.
Rob Kennedy
@Rob: 8 bytes, actually, in D2010.
Mason Wheeler
+3  A: 

You've hit upon a snag with using records.

Consider this code:

function Test: TTest;
begin
    ...
end;

Test.a := 1;

What your code looks like to the compiler is actually this:

TTest temp := Test;
temp.a := 1;

The compiler is telling you, with the error message, that the assignment is pointless, since it will only assign a new value to a temporary record value, which will be instantly forgotten.

Also, the @List[10] is invalid because List[10] again returns only a temporary record value, so taking the address of that record is rather pointless.

However, reading and writing the whole record is OK.

So to summarize:

List[10] := A;  <- writing a whole record is OK
List[10].a:=1;  <- List[10] returns a temporary record, pointless assignment
P:=@List[10];   <- List[10] returns a temporary record, its address is pointless
Lasse V. Karlsen
However the property items is read-write, and i think delphi could understand that Items[1].a:=123 meens Items[1]:=TType(123,oldval2,oldval3)
Astronavigator
But it doesn't... The important part is not what the compiler *could* do, but what it *actually does*.
Lasse V. Karlsen
@Astronavigator: Yes, the property is R/W, but you are not accessing the field directly. It just return a copy of the field. Check Mason's answer to work around this.
Ken Bourassa
A: 

If you want to store records, dynamic arrays are more suited to handling them :

type TTest = record a,b,c : Integer end;
type TTestList = array of TTest;
var List:TTestList;
    A:TTest;
    P:Pointer;
....
....

SetLength( List, 20 );
List[10]   := A; //<- OK
List[10].a := 1; //<- Ok
P := @List[10];  //<- Not advised (the next SetLength(List,xx) will blow the address away),
                 //   but technically works

If you need to add methods to manipulate these data, you can store this array as the field of a class, and add your methods to this class.

LeGEC