Jump to content
Dave Novo

How to access/modify underlying records of IList<T>

Recommended Posts

Hello,

 

If I make a list<T> where T is a record, what is the best way to get access to the actual records in the list to make modifications to them?

 

If I was using the built in TList<T> I would use the .List<T>, but Spring4D.IList<T> does not have a property to access the raw list. Is there another way to get access to the actual record instance in the list in order to modify it.

 

calling .Items makes a copy of the underlying record it seems and if I try to enumerate through the list using the enumerator and set a property on the variable in the enumerator I get an error that I cannot set a control loop variable.

Share this post


Link to post

I don't use Spring4D but maybe you could create a record method that returns a pointer to the record:

type
  PMyRecord = ^TMyRecord;
  TMyRecord
    ...lots of stuff here...
    function Data: PMyRecord;
  end;

function TMyRecord.Data: PMyRecord;
begin
  Result := @Self;
end;

begin
  var MyList := IList<TMyRecord>;
  ...
  var SomeData: PMyRecord := MyList[123].Data;
  ...
end;

I don't know if the list property getter will create an implicit copy of the record in this case but if it doesn't then the above should work.

 

Share this post


Link to post

IList<T> supports IArrayAccess<T>.

 

Here's an example:

procedure p();
type
    TRecord = record
        number: Byte;
    end;
begin
    const items = TCollections.CreateList<TRecord>();

    var item := Default(TRecord);
    item.number := 42;
    items.add(item);


    // Replace item at index 0 with a new one
    var newItem := items[0];
    Inc(newItem.number);
    items[0] := newItem;
    WriteLn(items[0].number);


    // or use IArrayAccess<T>
    var arrayAccess: IArrayAccess<TRecord>;
    Assert( Supports(items, IArrayAccess<TRecord>, arrayAccess) );
    Inc(arrayAccess.Items[0].number);
    WriteLn(items[0].number);
end;

 

Share this post


Link to post
20 minutes ago, Der schöne Günther said:

Assert( Supports(items, IArrayAccess<TRecord>, arrayAccess) );

Nice - but please don't use Assert like that in actual code.

Share this post


Link to post

It would be cool if the enumerator supported pointer access to the underlying element. Something like

 

for var curPtr in List.Pointers<PRecord> do
begin
    curPtr.SomeValue:=1;
 end

In the case above, the Pointers record would return a pointer to the underlying item, cast to the pointer type passed in as T. This can be useful for records (and maybe other) to deal with a pointer to the underlying items

Share this post


Link to post
1 hour ago, Dave Novo said:

It would be cool

Spring4d does provide you with access to the array of values using IArrayAccess, but what you ask is not spring4d specific.  It applies to any array of records. e.g.

type
  TMyRec = record
    StrField: string;
  end;
 TMyRecArray = TArray<TMyRec>;

 

To modify the values you need iterate using an index

var 
  RecArr: TMyRecArray

for var I := 0 to Length(RecArr) - 1 do
   RecArray[I].StrField := ...

 

Unfortunately you cannot do:

for var Rec in RecArr do
  Rec.StrField := ...  // <- compiler error: You cannot modify a for loop variable.

and in any case what you get in Rec above is a copy of the record not the original one.  I agree it would be cool to have an iterator that gives access to the underlying element.

 

Edited by pyscripter

Share this post


Link to post
1 hour ago, Dave Novo said:

It would be cool if the enumerator supported pointer access to the underlying element.

I have something like that in the works already.

 

5 hours ago, Anders Melander said:

I don't know if the list property getter will create an implicit copy of the record in this case but if it doesn't then the above should work.

It does create a copy (records are value types, what else should it do?) - what you are proposing is dangerous and error-prone.

 

55 minutes ago, pyscripter said:

Spring4d does provide you with access to the array of values using IArrayAccess, but what you ask is not spring4d specific.

That is not the case anymore in 2.0 - that interface has been removed from lists.

Edited by Stefan Glienke
  • Like 1

Share this post


Link to post
Just now, Stefan Glienke said:

I have something like that in the works already.

Would that work with any TArray as well?

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×