News for hackers. Stuff that matters.
Re:Closures and Objects Are Equivalent (2013) by int_19h on Sunday November 20, 2022 @05:07AM (#33679753)
In GCC, local functions are both closures and first-class values. I'm not entirely sure how it's implemented on all architectures, but on x86, when you convert such a function to a function pointer, a stub is dynamically generated on the stack (which thus has to be executable) that pushes the frame pointer on top of all the arguments before jumping to the actual implementation, and the pointer then points at that stub.

In standard Pascal, functions are closures but not first-class values (can be passed as arguments to other functions, but cannot be returned or assigned to variables); a typical implementation would implement a function pointer as a tuple of function address and pointer to stack frame. Some dialects - notably, Turbo Pascal - don't allow pointers to local functions at all.

Re:Closures and Objects Are Equivalent (2013) by fm77 on Sunday November 20, 2022 @06:44AM (#33680180)
> In standard Pascal, functions are closures but not first-class values (can be passed as arguments to other functions, but cannot be returned or assigned to variables)

Interesting - being an absolute non-expert in closures - but isn't it the other way around? That is, in Pascal, functions are first-class values but not closures?

Unless I am miss something here, but functions can be assigned to variables:

  function add(a,b:integer):integer; { far; in Turbo Pascal }
  begin
    add := a + b;
  end;

  type MyFunc = function (a,b:integer):integer;

  var f:MyFunc;
      x:integer;

  begin
    f := add; { here we assigning a function to a variable }
    x := f(3,4);
  end;
> Some dialects - notably, Turbo Pascal - don't allow pointers to local functions at all.

I know what you mean here, but that's not entirely true. In Turbo Pascal you had two ways to receive a pointer to a function:

1.) the way just shown, and here you are right, Turbo Pascal doesn't allow local functions, but that’s because how local functions in Turbo Pascal were implemented. Local functions have a hidden parameter (a 16-bit pointer to the caller's stackframe) pushed onto the stack, how do you handle this hidden parameter when you deal with a function pointer with a defined function signature? To avoid headaches I guess Hejlsberg simply choose to not allow local functions here.

2.) via a regular pointer - you simply store the function address in a pointer variable (or pass the function address to a pointer parameter), so:

  procedure MyProc;

  { a local function }
  function sub(a,b:integer):integer; { far; in TP }
  begin
    sub := a - b;
  end;

  type MyFuncHidden = function (a,b:integer; hidden:word):integer;

  var p:pointer;
      x:integer;

  begin
    p := @sub; { assigning a local function to a variable }
    x := MyFuncHidden(p)(7,8,0);
  end;
The problem here, now you as a programmer are in charge of handling the parameter passing.

Look at the implementation of ForEach/FirstThat in the Turbo Vision library. Both ForEach and FirstThat accept local functions as parameter (and only local functions).

Re:Closures and Objects Are Equivalent (2013) by int_19h on Sunday November 20, 2022 @04:58PM (#33685860)
Function pointer types are a Turbo Pascal extension; in standard (Wirth/ISO) Pascal, you cannot have "type = function" etc, you can only use that syntax to declare arguments of function type. So they're not first-class values. They're closures because they capture the enclosing environment (variables).

In your second example, what you're doing is the equivalent of reinterpret_cast between two incompatible pointer types (if they were compatible, you could have just assigned @sub to a variable of type MyFuncHidden). You cannot safely assume that your new signature faithfully corresponds to what the compiler does under the hood - that's an implementation detail. Furthermore, in this case, your function doesn't even try to access variables from the outer scope, and this would break if it did.