XE7’s new dynamic array syntax – take 2

XE7’s new dynamic array syntax – take 2

The syntax change also introduced a new ambiguity between argument types array of type and array of const.

Not sure that it is the appropriate error – as you should not be able to pass [] as an argument to a var parameter?

program XE7Tests2;

{$APPTYPE CONSOLE}

{$R *.res}

uses

  System.SysUtils, Variants;

type

  TVarArray = array of Variant;

  TTest = class

    function StoredProc(ConstParams: array of const): integer; overload;

    function StoredProc(var Params: TVarArray): integer; overload;

  end;

{ TTest }

function TTest.StoredProc(ConstParams: array of const): integer;

begin

end;

function TTest.StoredProc(var Params: TVarArray): integer;

begin

end;

var

  Test: TTest;

begin

  Test := TTest.Create;

  try

    try

      Test.StoredProc([]);  

// [dcc32 Error]: E2251 Ambiguous overloaded call to ‘StoredProc’

// Related method: function TTest.StoredProc(array of const): Integer;

// Related method: function TTest.StoredProc(var TVarArray): Integer;

    except

      on E: Exception do

        Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

  finally

    Test.Free;

    Write(‘ – Enter: ‘);

    Readln;

  end;

end.

XE7’s new dynamic array syntax

XE7’s new dynamic array syntax

Good thing: Empty arrays can be used as default param value.

    procedure Test(const Params: TVarArray = []);

Bad thing: Variants not fully supported?

Try uncommenting CVarArr in the example below.

Doesn’t work and gives “Constant expression expected”.  

Yet the same constant list can be assigned to VVarArr

Go figure.

program XE7Tests;

{$APPTYPE CONSOLE}

{$R *.res}

uses

  System.SysUtils, Variants;

type

  TVarArray = array of Variant;

  TIntArray = array of Integer;

  TTest = class

    procedure Test(const Params: TVarArray = []);

  end;

{ TTest }

procedure TTest.Test(const Params: TVarArray);

var

  npar: Integer;

begin

  npar := High(Params) – Low(Params) + 1;

  Writeln(nPar);

end;

const

  CIntArr: TIntArray = [1,2,3];

//  CVarArr: TVarArray = [1,’2′, 3];  // “Constant expression expected”

var

  Test: TTest;

  VVarArr : TVarArray;

  VIntArr : TIntArray;

begin

  Test := TTest.Create;

  try

    try

      Test.Test;      // 0

      Test.Test(nil); // 0

      Test.Test([1,’2′, 3]); // 3

      VVarArr := [1,’2′, 3, 3.14];

      Test.Test(VVarArr); // 4

      Test.Test(VVarArr + [‘five’]); // 5

//      Test.Test(VVarArr + CVarArr); // Should have been 7

    except

      on E: Exception do

        Writeln(E.ClassName, ‘: ‘, E.Message);

    end;

  finally

    Test.Free;

    Write(‘ – Enter: ‘);

    Readln;

  end;

end.

 

Type inference and inline declarations

Type inference and inline declarations

(Copied from a comment I wrote on Non-tech.)

I would like to see more scope fencing through inline declarations and automatic type inference.

for aItem in myList do if Pos( ‘widget’, aItem ) > 0 then listbox1.Items.Add( aItem ); 

aItem doesn’t really need a declaration if the list is a TList or in any other way expose a type through the default property.

Should I need to cast the type of an iteration variable, it could be done like: for aItem:String in myList – and still be possible to type check at compile time.

I think inline declaration would be very good for iterators – so that you don’t mix variable and iterator use – such as first using it in a for loop iteration and later reuse it as a reference variable.

Scope limited temporary variables would also be great. 

Alt.1

using A:TThisType, B:TThatType

begin

// The simple reference variables A and B only exists within this scope. 

end;

Alt.2

using auto A:TThisType, B:TThatType

begin

// A and B are created on entering and destroyed on exiting this scope. 

end;

And then there is the dreaded with statement which could be replaced by a type inferred reference

using A as Some.Object.List[Index]

begin

  // A only exists within this scope

  A.Value := ..

end

A would be typed from the list element type, and if you need a cast

using A:TSomeType as Some.Object.List[Index]

begin

  // A only exists within this scope

  A.Value := ..

end

That would also be type checkable at compile time.