__Delete runs when the object is deleted. The object is deleted when its last reference is released. To control the order of __Delete, you must control the order in which object references are released.
There is no "stack" here, only a list of variables and some independent objects.
The order of release for objects in global/static variables during program exit is undefined. You cannot rely on it. No guarantees will be given about the order in future. If anything changes, it will probably be to remove the automatic release of global/static variables entirely, since it is inconsistent with local variables (which aren't released when the program exits, only if the function returns before that happens) and there is no possible way for the program to determine the
ideal order.
I assume in a real-world script, you would be using local variables for these handles, not global variables. The order in which local variables are freed when the function returns is also undefined.
C++ objects on the stack have their lifetime directly determined by the compiler, long before the program runs. The compiler inserts destructor calls into the compiled code at the appropriate points. If you take the object's address and then let the object go out of scope, the address becomes invalid. By contrast, AutoHotkey's objects are all independently dynamically allocated and reference counted. If you assign the reference to another variable, the object's lifetime then depends on both variables.
Although the interpreter could go to extra effort to maintain the order that the
variables were "created" in order to free them in the reverse order, the variables are not the objects. A variable can be repeatedly assigned different objects during a single function call. An object can be assigned to multiple variables or properties. It is also unclear what actual order variables are "created" in. In the current implementation of v2, variables are created when the script loads (the script is "semi-compiled" at startup), in the order that the assignments/declarations/&references are
encountered, which is not necessarily the order that they will be evaluated in. If you wanted it to be in reverse order of initialized, or most to least recent assignment, there would be a runtime cost (and it would never be implemented).
There are any number of ways to solve the problem you demonstrate. If the second object is dependent on the first object like you demonstrate with the handles, your implementation can reflect that.
Code: Select all
class Test {
__New(name, keep_alive?) {
this.my_name := name
if IsSet(keep_alive)
this.keep_alive := keep_alive
}
__Delete() {
MsgBox this.my_name
}
}
v1 := Test("First")
v2 := Test("Second", v1)