But why is this only possible with inline definitions?
There are two types of const, there are untyped and typed consts. Untyped consts are compile time only constructs, basically macros. They cannot have runtime implications. E.g.
const
C = 42;
begin
WriteLn(C);
WriteLn(C);
end;
// Is runtime translated to
begin
WriteLn(42);
WriteLn(42);
end;
The constant does not exist after compilation anymore and can therefore not exerpt any runtime behavior. If what youve wrote is an untyped constant, the following would happen:
const someproc = procedure ()
var a: TBar;
begin
end;
someproc();
someproc();
// Would be translated to
procedure ()
var a: TBar;
begin
end();
procedure ()
var a: TBar;
begin
end();
Note that because at runtime those are two completely different instantiations, there is no connection between the two "A" variables here, so no state is captured in between.
The alternative are typed constants, which is a misnomer, as in reality they are just static (global) lifetime local scope variables, and then what you posted is in reality just them in combination with type inference, so
const someproc = procedure ()
var a: TBar;
begin
end;
// is just
const someproc: reference to procedure = procedure()
var a: TBar;
begin
end;
But then there is absolutely no difference from doing that:
const
someproc: reference to procedure = nil;
begin
if not Assigned(someproc) then
someproc = procedure()
var
a: TBar;
begin
end;
end;
This construct can be used in functional programming to capture outer variables into a local context.
(Local visibility, but global lifetime, until the context is not referenced anymore and released)
Thats not from functional programming but from prototypical programming, which is often clustered together, due to it's reliance on runtime function manipulation, but there is a big difference, functional programming is stateless ("pure") and there is no concept of variables or variable lifetime. A real functional program is so pure that it doesn't even require your computer to be powered to run.
But thats just on a side note. More importantly, this is used in such languages to emulate the behavior of static lifetime variables (such as writable consts in pascal), which those languages are usually lacking. So you are currently introducing a hack to emulate a hack that tries to emulate a feature we already have.
Just skip the middle man:
const
GlobalLifetimeA: TBar = nil;
var
a: TBar;
begin
if not Assigned(GlobalLifetimeA) then
GlobalLifetimeA := a;
end;
What I think pascal is truely missing is truely constant typed consts that can be assigned later, something like this:
const
MyConst: Integer; // Note no assignment here
begin
WriteLn(MyConst); // Not assigned yet, compiler error
MyConst := 42; // first assignment, will be unchangable from now
WriteLn(MyConst); // Works because already defined
MyConst := 32; // Compiler error: trying to reassign const
end;
Maybe even with a special keyword to make this more clear:
const
MyConst: Integer; unassigned; // Note no assignment here
begin
assign MyConst := 42;
MyConst := 32; // error
assign MyConst := 32; // error
end;
But a real notion of consts is what is defenitely lacking