Want direct capture of nested procedure/function into a reference to procedure/function to work (for anonymous procedures/functions)

Summary

  • Indirect capture of a nested procedure works, direct capture does not always work.
  • Would like equal capture of everything in the parent/containing scope.

System Information

  • Operating system: Linux, FreeBSD (but should work for All)
  • Processor architecture: x86-64, AARCH64 (but should work on All)
  • Device: Computer (but should work on all)

Example Project

This does not work, a direct capture of nested procedure.

{$mode delphi}
{$modeswitch anonymousfunctions}
{$modeswitch functionreferences}

program nocapture;

type
  tSimpleProc = reference to procedure;

procedure main;

  var
    tcf: tSimpleProc;
    x: integer;

  procedure nested;
    begin
      writeln ('Hello from nested! x: ', x);
      inc(x);
    end;

  begin
    x := 100;

    tcf := procedure begin nested; end;
    tcf();
    tcf();

  end;

begin
  main;
end.

The above results in:

Free Pascal Compiler version 3.3.1 [2022/09/26] for x86_64
Copyright (c) 1993-2022 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling src/nocapture.pas
nocapture.pas(25,28) Error: Symbol "nested" can not be captured
nocapture.pas(34) Fatal: There were 1 errors compiling module, stopping
Fatal: Compilation aborted
Error: /home/shared-development/fpc_usr/lib/fpc/3.3.1/ppcx64 returned an error exitcode

This does work, example includes indirect capture to get the nested procedure to be captured.

{$mode delphi}
{$modeswitch anonymousfunctions}
{$modeswitch functionreferences}

program doescapture;

type
  tSimpleProc = reference to procedure(const n: integer);

procedure main0;

  var
    tcf: tSimpleProc;
    tcf2: tSimpleProc;
    x: integer;

  procedure nested(const n: integer);
    begin
      writeln ('Hello from nested! ', n, ' x: ', x);
      inc(x);
    end;

  begin
    tcf := nested;
    x := 100;

    procedure(const aArg: String) begin Writeln(aArg); end('Hello World');
    procedure begin nested(1); end();
    tcf2 := procedure(const n: integer) begin tcf(n); end;
    tcf2(2);
  end;


procedure main1;
  var
    x: integer;

  begin
    x := 132;
    procedure begin writeln ('x = ', x) end();
  end;

begin
  main0;
  main1;
end.

Produces this output:

Hello World
Hello from nested! 1 x: 100
Hello from nested! 2 x: 101
x = 132

Relevant background information

See Strange capture denial and acceptance for Anonymous Functions and Function refs on the Lazarus forums.