I wish __Delete() runs in stack order.

Propose new features and changes
pidgay
Posts: 16
Joined: 21 Aug 2017, 02:32

I wish __Delete() runs in stack order.

26 Dec 2022, 21:21

Code: Select all

class Test {
	__New(name) {
		this.my_name := name
	}
	__Delete() {
		MsgBox this.my_name
	}
}
v1 := Test("First")
v2 := Test("Second")
expect: Second -> First
result: First -> Second

If I change variable name like below,

Code: Select all

v3 := Test("First")
v2 := Test("Second")
result is Second -> First as I expected.
It seems to follow the order of the variable's name, not creation/initialization order.

This causes problems when using some Win32 functions.

Code: Select all

/*  C/C++  */
HANDLE h1 = Step1Func(...);
HANDLE h2 = Step2Func(h1, ...);
CloseHandle(h2);
CloseHandle(h1);
These handles are connected sequentially. So their destruction must be reverse sequential.
In this AHK system, it is difficult to perfectly imitate the smart pointer of C++.
Inevitably, I'm using a class that stores multiple handles and has a specific destruction order.
Of course, this is inconvenient and exhausted because destruction order has to be modified in each situation.
English is difficult...
lexikos
Posts: 9624
Joined: 30 Sep 2013, 04:07
Contact:

Re: I wish __Delete() runs in stack order.

27 Dec 2022, 01:51

__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)
pidgay
Posts: 16
Joined: 21 Aug 2017, 02:32

Re: I wish __Delete() runs in stack order.

27 Dec 2022, 06:12

lexikos wrote: 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.
lexikos wrote: By contrast, AutoHotkey's objects are all independently dynamically allocated and reference counted.
lexikos wrote: 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).
I missed the fact that different languages have different characteristics, especially a huge runtime cost in the interpreter language.
I was used to the defined behavior of a particular language. And I only thought that way.
lexikos wrote: If the second object is dependent on the first object like you demonstrate with the handles, your implementation can reflect that.
In fact, I have deliberately ruled out that 'reference-counting' way of increasing dependency.
This is because the process of deleting objects does not seem intuitive to me with poor debugging skills.
After all, the method of using reference count like shared_ptr of C++ seems to be the best.
Thank you! :D
English is difficult...

Return to “Wish List”

Who is online

Users browsing this forum: Descolada and 9 guests