Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to distinguish between an Argumentless Call and a Function Reference in an Assignment

Tags:

delphi

In an assignment, how can I distinguish between assigning the return value of a function that takes no parameters (and therefore the call may have no parens), and assigning the function reference itself. Is it only by looking at the type of the receiving variable?

Here is a code fragment for illustration (Delphi noob here):

type
   TIntFun = function():integer;
var
   IntFun : TIntFun;
   I : integer;
function AnIntFun(): integer;
begin
  result := 3;
end;
begin
  I := AnIntFun;  // argumentless call, returning 3
  IntFun := AnIntFun; // function assignment?
end
like image 435
ThomasH Avatar asked Oct 15 '19 08:10

ThomasH


2 Answers

Is it only by looking at the type of the receiving variable?

Yes.

This is, in my view, a strong argument against allowing the function call syntax to omit parens. If that language feature did not exist, then you would have to write:

I := AnIntFun();
IntFun := AnIntFun;

If you were forced to write it this way then the compiler would regard

I := AnIntFun; 

as a syntax error. The expression AnIntFun would always be of procedural type and the compiler (and the reader) would not need to rely on context to determine the type of the expression.

Relying on context to determine the type of the expression is very undesirable. Consider for instance function overloading:

procedure foo(fun: TIntFun); overload;
procedure foo(val: Integer); overload;

When you write:

foo(AnIntFun);

which overload do you think is chosen? If the language required parens on every function call then AnIntFun is always of procedural type, and the first overload would be chosen without ambiguity.

like image 87
David Heffernan Avatar answered Sep 26 '22 18:09

David Heffernan


Your code will work as expected.

But to be explicit, you can write AnIntFun() if you want to execute the function and @AnIntFun if you mean the function itself.

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  TIntFcn = function: Integer;

procedure Test(Val: Integer); overload;
begin
  Writeln('Value: ' + Val.ToString);
end;

procedure Test(Fcn: TIntFcn); overload;
begin
  Writeln('Function. Returned value: ' + Fcn.ToString);
end;

function TestFcn: Integer;
begin
  Result := 3;
end;

begin
  Test(TestFcn()); // value (obvious)
  Test(@TestFcn); // fcn (obvious)
  Test(TestFcn); // value
  Readln;
end.
like image 29
Andreas Rejbrand Avatar answered Sep 24 '22 18:09

Andreas Rejbrand