Page 1 of 1

nested-functions ByRef parameters

Posted: 31 Mar 2018, 17:04
by arcticir
I did not see restrictions on ByRef parameters in the "nested-functions" document.
Is this a normal mistake?

Code: Select all

Error:  ByRef parameters cannot be upvalues.

Specifically: a

	003: test()
	004: {
	005: t()
--->	006: {
	007: MsgBox(a)
	008: }
	010: }
	011: Exit

Code: Select all


test(byref a){
		MsgBox a

Re: nested-functions ByRef parameters

Posted: 31 Mar 2018, 20:33
by lexikos
You didn't look hard enough.
By default, a nested function may access non-dynamic local and static variables of any function which encloses it, but not ByRef parameters or variables which are created dynamically.
Source: Nested Functions
In AutoHotkey, all non-dynamic variable references are resolved at the moment the script launches, including local variables. Each function has one set of local variables which exist from the moment the script launches until it exits. The code within the function contains pointers to these variables. Recursion is handled by backing up the local variables when a second layer of the function begins and restoring them after it returns, so at any one time, the local variables belong to the top layer of the function.

Closures may be associated with any layer of a function still running, or a set of variables from a function which has since returned. So obviously, they can't refer to the "top-layer" local variables described above. What they need are "free variables", which are not tied to the top layer of the function, are not freed when the function returns, and are able to exist for as long as a closure refers to them.

Closures are implemented by detecting which variables need to be "free variables", allocating those when the outer function begins, and turning the top-layer variables in the outer and inner function into aliases of the free variables. ByRef parameters, on the other hand, accept a reference to a variable which may or may not be "free". It is impossible to tell (with certainty) at load time whether a variable is going to be passed to a ByRef parameter, since functions can be called dynamically or via objects. At the time the closure is created, it is impossible to tell which function the variable came from, and too late to convert it into a free variable.

The only feasible solution within the current framework would be to make all local variables "free", but this would reduce performance for the majority of scripts. ByRef parameters could be allowed within a limited context (when the nested function is called directly, not via a closure), but that requires either greater complexity to detect when it is used incorrectly, or allowing incorrect usages which behave counter-intuitively (the parameter behaving as non-ByRef or referring to the wrong variable).

Re: nested-functions ByRef parameters

Posted: 01 Apr 2018, 18:19
by arcticir
I am sorry for my carelessness. Thank you very much for your patience. :)

My script is used to exchange data between processes. It makes heavy use of subtags within functions. Now the nested function seems to be better able to implement its functionality. In addition to the restrictions from ByRef parameters.

Code: Select all

link(this:="__",byref label:="",byref key:="",byref value:="",param*){
    static list:={"add":1,"call":1,"dyna":1,"dynatoken":1,"func":1,"funclink":1,"funclist":1,"get":1,"go":1
    if list[type]
        Gosub("_" type)
        While to and list[to]
    return out

Re: nested-functions ByRef parameters

Posted: 21 Apr 2018, 16:22
by Flipeador
Is this a bug?

Code: Select all

MsgBox f()

    local a := ""
    return a
        a := "aaaaaaaaaaaaaaa"    ; if you remove an "a", it works correctly

Edit* It seems that it has already been fixed.