Jump to content
PeterPanettone

Open Type Arrays?

Recommended Posts

2 hours ago, Kas Ob. said:

wonder if there is trick(s) to make this works 

No - Anything is an untyped var parameter - if you put such a signature into an interface with methodinfo on you even get a funky compiler error E2134 Type '<void>' has no type info

Share this post


Link to post
7 hours ago, Kas Ob. said:

I wonder if there is trick(s) to make this works :classic_biggrin:

Not the way you have shown, no.  All type info is lost with an untyped var parameter, so you HAVE to specify a type somehow.  A Generic is the most direct way to specify a type in a, well, generic manner, eg:

type
  TRecSI = record
    FInteger: Integer;
    FString: string;
    constructor Create(const s: string; i: Integer);
  end;

  THelper = class
    class procedure DoSomething<T>(var Anything: T);
  end;

constructor TRecSI.Create(const s: string; i: Integer);
begin
  FInteger := i;
  FString := s;
end;

class procedure THelper.DoSomething<T>(var Anything: T);
begin
  case GetTypeKind(T) of
    tkInteger:
      Writeln(PInteger(@Anything)^);
    ///
  end;
end;

var
  A: Integer;
  B: string;
  C: TArray<Byte>;
  D: TArray<Integer>;
  E: TArray<string>;
  F: TRecSI;

begin
  THelper.DoSomething(A);
  THelper.DoSomething(B);
  THelper.DoSomething(C);
  THelper.DoSomething(D);
  THelper.DoSomething(E);
  
  F := TRecSI.Create('Hello', 1234);
  DoSomething(F);

  Readln;
end.

Otherwise, you could use TValue instead, eg:

type
  TRecSI = record
    FInteger: Integer;
    FString: string;
    constructor Create(const s: string; i: Integer);
  end;

constructor TRecSI.Create(const s: string; i: Integer);
begin
  FInteger := i;
  FString := s;
end;

procedure DoSomething(const Anything: TValue);
begin
  case Anything.Kind of
    tkInteger:
      Writeln(Anything.AsInteger { or: Anything.AsType<Integer> } );
    ///
  end;
end;

var
  A: Integer;
  B: string;
  C: TArray<Byte>;
  D: TArray<Integer>;
  E: TArray<string>;

begin
  // TValue supports implicit conversions for some fundamental types...
  DoSomething(A { or: TValue.From(A) });
  DoSomething(B { or: TValue.From(B) });

  // but no implicit conversions for array types...
  DoSomething(TValue.From(C));
  DoSomething(TValue.From(D));
  DoSomething(TValue.From(E));
  
  // or records...
  DoSomething(TValue.From(TRecSI.Create('Hello', 1234)));

  Readln;
end.

 

Share this post


Link to post
17 minutes ago, Remy Lebeau said:

TValue supports implicit conversions for some fundamental types but no implicit conversions for array types or records...

If we just could write

class operator Implicit<T>(const value: T): TValue;

... oh wait... we can!

 

type
  TValueHelper = record helper for TValue
    class function &&op_Implicit<T>(const value: T): TValue; static;
  end;

class function TValueHelper.&&op_Implicit<T>(const value: T): TValue;
begin
  TValue.Make(@value, System.TypeInfo(T), Result);
end;

 

  • Like 2

Share this post


Link to post
1 hour ago, Stefan Glienke said:

If we just could write


class operator Implicit<T>(const value: T): TValue;

... oh wait... we can!

 


type
  TValueHelper = record helper for TValue
    class function &&op_Implicit<T>(const value: T): TValue; static;
  end;

class function TValueHelper.&&op_Implicit<T>(const value: T): TValue;
begin
  TValue.Make(@value, System.TypeInfo(T), Result);
end;

 

Very excellent Stefan ! 

Just noticed that the new operand overrides the original one for integer-literal :

DoSomething(1);      // calls yours operand.
DoSomething(a);      // calls default operand. a=integer.
DoSomething('test'); // calls default operand.
DoSomething(str);    // calls default operand. str=string.

EDIT:

I guess the answer is here:

class operator TValue.Implicit(Value: Integer): TValue;

 

 

Edited by Mahdi Safsafi

Share this post


Link to post
54 minutes ago, Mahdi Safsafi said:

Just noticed that the new operand overrides the original one for integer-literal

Yes, because 1 is not Integer

Share this post


Link to post
21 hours ago, PeterPanettone said:

However, your employer has to pay for the time you need to write overloaded code. (Though I assume you're a fast writer).

These overloaded methods are like 4 lines. I really would like to have an employer who pays me double for 4 extra lines per feature request.

In a real world scenario, overloaded methods usually point from one to the other (or call the "real" one with proper adjustments) so we can argue that this was for demonstration only, but in real life - multiple overloaded methods will not consume even 10 minutes of your time if done smartly.

Share this post


Link to post

United types are a headache in JS/TS... you must always check whether that 'foo' is number, or string, or maybe string object, or undefined, or null... Overloaded methods rule. Compiler takes care of correct branching so you can't forget some type check and ruin your app.

One addition I'd add to generics is "is" operator for simple types. Nevertheless, "de-generising" a type is a bad practice that should be avoided so I doubt is would be added to language

Edited by Fr0sT.Brutal

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

×