Reputation: 76597
If I have a TFunc<T: class>
a variable of that type will allow me to do dereference the class members directly.
Even class completion supports it.
If however I have an array of TFunc<T>
's 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.
Upvotes: 4
Views: 324
Reputation: 613003
Pascal allows the parens to be omitted when calling a function or procedure that has no parameters. In your code SingleObject
is a function, and
SingleObject.Test
is equivalent to
SingleObject().Test
There is an ambiguity here. When the parser encounters SingleObject
, it has to decide whether you mean to refer to the function, or to call it. The parser resolves that ambiguity by taking account of the context. In the example above, it decides that since you used the .
operator, you must have intended for the function to be called, and then have the .
operator applied to the value returned from that function call.
Now, for your array example, the parser appears to have trouble disambiguating. Personally I think that is an oversight. It is perfectly possible to disambiguate, so far as I can see.
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, only the array of reference function suffers the problem. My suspicion is that the compiler developers missed whatever steps are needed to handle this disambiguation when they added support for reference function types.
The work around is easy enough. You need to explicitly disambiguate:
ArrRefFunc[0]().Foo;
This entire issue steps from the decision in Pascal to allow function call parens to be omitted when the function has no parameters. In my opinion, given the issues with ambiguity that arise with modern programming styles, it would be nice to go back in time and change that decision.
Upvotes: 6