Why TFunc <T> respects, but array [0..1] TFunc <T> is not?

If I have TFunc<T: class>

, a variable of this type will allow me to dereference class members directly.
Even the class supports it.

enter image description here

If, however, I have an array TFunc<T>

, then this does not compile.
Why not? Is this a compiler error or is there some underlying reason?

program Project33;
{$APPTYPE CONSOLE}
uses
  System.SysUtils;

type
  TTestObject = class(TInterfacedObject, IInterface)
    procedure Test;
  end;

procedure TTestObject.Test;
begin
  WriteLn('Test');
end;

procedure Test;
var
  A: IInterface;
  TestObject: array [0..4] of TFunc<TTestObject>;
  SingleObject: TFunc<TTestObject>;
  i: integer;
begin
  for i:= 0 to 4 do begin
    a:= TTestObject.Create;
    TestObject[i]:= function: TTestObject
    begin
      Result:= a as TTestObject;
    end;
    TestObject[i].Test;   //<<-- does not compile
    SingleObject:= TestObject[i];
    SingleObject.Test;   // <<-- works.
  end;
end;

begin
  Test; ReadLn;
end.

      

+3


source to share


1 answer


Pascal allows you to ignore parsers when calling a function or procedure that has no parameters. You SingleObject

have a function in your code and

SingleObject.Test

      

equivalent to

SingleObject().Test

      

There is ambiguity here. When the parser is encountered SingleObject

, it must decide if you want to refer to the function or call it. The parser resolves this ambiguity by taking context into account. In the above example, it decides that since you used an operator .

, you should have pointed to the function to call, and then apply the operator .

to the value returned from that function call.

Now, for your array example, the parser seems to have ambiguity issues. Personally, I think this is an oversight. As far as I can see, it is quite possible to unambiguously eliminate.



Consider this program:

type
  TRec = class
    procedure Foo; virtual; abstract;
  end;

  TFunc = function: TRec;
  TFuncOfObj = function: TRec of object;
  TRefFunc = reference to function: TRec;

var
  ScalarFunc: TFunc;
  ArrFunc: array [0..0] of TFunc;
  ScalarFuncOfObj: TFuncOfObj;
  ArrFuncOfObj: array [0..0] of TFuncOfObj;
  ScalarRefFunc: TRefFunc;
  ArrRefFunc: array [0..0] of TRefFunc;

begin
  ScalarFunc.Foo; // fine
  ArrFunc[0].Foo; // fine
  ScalarFuncOfObj.Foo; // fine
  ArrFuncOfObj[0].Foo; // fine
  ScalarRefFunc.Foo; // fine
  ArrRefFunc[0].Foo; // E2003 Undeclared identifier: 'Foo'
end.

      

As you can see, the problem is only solved in the reference function array. My suspicion is that the compiler designers missed any steps needed to clear up this ambiguity when they added support for function reference types.

Working around is simple enough. You need to explicitly fix the problem:

ArrRefFunc[0]().Foo;

      

This whole problem comes from a solution in Pascal to allow parens call functions to be ignored when the function has no parameters. In my opinion, given the ambiguity problems with modern programming styles, it would be nice to go back in time and change that decision.

+5


source







All Articles