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.
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.
source to share
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.
source to share