Recent

Author Topic: Retrieving a function variable type from inside the same function  (Read 3106 times)

Kibukj

  • Newbie
  • Posts: 4
Consider this standard (ISO) Pascal code:
Code: [Select]
program test(output);

procedure call(n: integer; function f(n: integer): integer);
begin
  writeln(f(n))
end;

function f(n: integer): integer;
begin
  f := n;
  if n > 0 then call(n - 1, f)
end;

begin
  call(3, f)
end.

The output should be
Code: [Select]
0
1
2
3

This compiles fine with {$mode iso} using FPC's trunk version, but can it be translated to {$mode fpc} or {$mode objfpc}?

The main difference AFAIK is that these modes require @ to distinguish procedural/functional types from procedure/function calls (and in some cases, but not here, () to do the opposite). We should also need {$modeswitch nestedprocvars}, since it should work with nested procedures/functions too, and procedure "call" uses a functional parameter.

Code: [Select]
program test;

{$modeswitch nestedprocvars}

procedure call(n: integer; function f(n: integer): integer);
begin
  writeln(f(n))
end;

function f(n: integer): integer;
begin
  f := n;
  if n > 0 then call(n - 1, @f)
end;

begin
  call(3, @f)
end.

But this results in an error
Code: [Select]
Error: Incompatible type for arg no. 2: Got "Pointer", expected "<procedure variable type of function(SmallInt):SmallInt is nested;Register>referring to @f. It makes sense, since f is the function result variable inside function f, @f might be a pointer to the current function result.

Is there another way to get a functional variable/function pointer from inside the same function when using {$mode fpc} and {$mode objfpc}? In other words, is there a way to specify I want a function variable for the function named "f", not a pointer to the function result variable named "f"?

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Retrieving a function variable type from inside the same function
« Reply #1 on: January 30, 2015, 02:23:31 am »
it works using @test.f

Kibukj

  • Newbie
  • Posts: 4
Re: Retrieving a function variable type from inside the same function
« Reply #2 on: January 30, 2015, 03:43:45 am »
it works using @test.f

Thanks, I didn't know the program name acted that way.

Is there a way to get this to work with nested procedures/functions as well?

Similarly, this ISO code works fine in trunk {$mode iso}:
Code: [Select]
program test(output);

procedure call(n: integer; function f(n: integer): integer);
var
  c: integer;
begin
  if n > 0 then c := f(n - 1)
end;

procedure a;
var
  c: integer;
 
  function b(n: integer): integer;
  begin
    writeln(n);
    b := n;
    call(n, b)
  end;

begin
  c := b(2)
end;

begin
  a
end.

but my attempt at translating this to {$mode fpc} runs into the same problem

Code: [Select]
program test;

{$modeswitch nestedprocvars}

procedure call(n: integer; function f(n: integer): integer);
var
  c: integer;
begin
  if n > 0 then c := f(n - 1)
end;

procedure a;
var
  c: integer;

  function b(n: integer): integer;
  begin
    writeln(n);
    b := n;
    call(n, @b)
  end;

begin
  c := b(1)
end;

begin
  a
end.

Code: [Select]
Error: Incompatible type for arg no. 2: Got "Pointer", expected "<procedure variable type of function(SmallInt):SmallInt is nested;Register>
@test.b unfortunately but understandably doesn't work. My next best guess was @test.a.b, however procedure identifiers don't seem to have the same property.
Code: [Select]
Error: Illegal qualifier
I have found one method of getting around this, which was to create a functional variable that is visible to b and initialised in a with a pointer to b
Code: [Select]
procedure a;
var
  c: integer;
  ab: function(n: integer): integer is nested;

  function b(n: integer): integer;
  begin
    writeln(n);
    b := n;
    call(n, ab)
  end;

begin
  ab := @b;
  c := b(1)
end;

but this seems a little sloppy.

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Retrieving a function variable type from inside the same function
« Reply #3 on: January 30, 2015, 05:38:36 am »
but this seems a little sloppy.
Is this sloppy enough?
Code: [Select]
procedure a;
var
  c: integer;

  function b(n: integer): integer;
    function ab(n: integer): integer;
    begin
      ab := b(n);
    end;
  begin
    writeln(n);
    b := n;
    call(n, @ab);
  end;

begin
  c := b(1)
end; 

 

TinyPortal © 2005-2018