Jump to content
RayTmsk

How to write several SetAs...Array procedures ?

Recommended Posts

Hi all!
I need to set object from several types of arrays:

procedure SetAsGuidArray(SourceItems: TArray<TGuid>);

procedure SetAsIntArray(SourceItems: TArray<integer>);

procedure SetAsStringArray(SourceItems: TArray<string>);

and so on...

 

What is modern way for do this without many code?
procedure SetAsAnyArray(SourceItems: TArray<??>);
will be good but impossible...

may be interesting way exist for such constructions ?

Share this post


Link to post

Please show the code for one "procedure SetAsGuidArray(SourceItems: TArray<TGuid>); " as an example

Share this post


Link to post

procedure TDataField.SetAsGuidArray(SourceItems: TArray<TGuid>);
begin
  DataType := ftArray;
  FArrayItemType := ftGuid;
  FDataArrayGuids := SourceItems;
end;
 

Share this post


Link to post
2 hours ago, RayTmsk said:

procedure TDataField.SetAsGuidArray(SourceItems: TArray<TGuid>);
begin
  DataType := ftArray;
  FArrayItemType := ftGuid;
  FDataArrayGuids := SourceItems;
end;
 

Are you sure this is right? It takes a reference to the array rather than a copy. 

Share this post


Link to post
6 hours ago, David Heffernan said:

Are you sure this is right? It takes a reference to the array rather than a copy. 

Not tested now but... I'd like to think it works the same way as the strings.
Reference at first assign and hard copy while changing.
 

Share this post


Link to post
37 minutes ago, RayTmsk said:

Reference at first assign and hard copy while changing.

That is true for strings, but nor for dynamic arrays.

  • Like 2

Share this post


Link to post
Posted (edited)
On 4/26/2024 at 7:49 AM, RayTmsk said:

What is modern way for do this without many code?

You can use a Generic so you have only 1 method to declare and implement which can accept multiple types as input, eg:

procedure TDataField.SetAsAnyArray<T>(SourceItems: TArray<T>);

But, it looks like you have different data members for each array type, so you would have to use RTTI to detect the actual type used for T and write different code branches to handle each type that you want T to accept.  That's not much better than just writing a separate method for each type of T.

Edited by Remy Lebeau

Share this post


Link to post
15 minutes ago, Uwe Raabe said:

That is true for strings, but nor for dynamic arrays.

Yes, you are right. But..

What about topic question?

Share this post


Link to post
16 minutes ago, Remy Lebeau said:

But, it looks like you have different data members for each array type, so you would have to use RTTI to detect the actual type used for T and write different code branches to handle each type that you want T to accept.  That's not much better than just writing a separate method for each type of T.

Hmm... but how to detect real type of T ? in first iterations I need for int, guid, string, float.
Any reference to vcl source or article, please... 🙂

Share this post


Link to post
18 minutes ago, RayTmsk said:

What about topic question?

Well, knowing what you are doing in the setter functions is likely important to decide how to write them. You want to take copies? And do you have one member field for each array type? 

 

Anyway, I'm also of the opinion that a branching generic method is little better than a series of overloads. 

Share this post


Link to post
5 minutes ago, David Heffernan said:

Well, knowing what you are doing in the setter functions is likely important to decide how to write them. You want to take copies? And do you have one member field for each array type? 

Yes, I want to do copies. As stupid decision  planning to create several internal array for hold data: FDataArrayGuids, FDataArrayStrings, FDataArrayIntegers...

 

I find good method as sample

unit System.Generics.Collections;
class function TArray.ToString<T>

Share this post


Link to post
4 hours ago, RayTmsk said:

Hmm... but how to detect real type of T ? in first iterations I need for int, guid, string, float.

For example:

procedure TDataField.SetAsAnyArray<T>(SourceItems: TArray<T>);
begin
  case GetTypeKind(T) of
    tkInteger: begin
      ...
    end;
    tkUString: begin
      ...
    end;
    tkFloat: begin
      ...
    end;
    tkRecord: begin
      if TypeInfo(T) <> TypeInfo(TGuid) then
        raise ...;
      ...
    end;
  else
    raise ...;
  end;
end;

 

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

×