Page 1 of 1

Automatic inclusion doesn't work with globals

Posted: 30 Jul 2020, 13:18
by venaci
According documentation
Files can be automatically included (i.e. without having to use #Include) by calling a library function by name.
(https://www.autohotkey.com/docs/commands/_Include.htm).
*it works if function and file names are identical

However it doesn't seem to work if library defines global variables e.g.

library code:

Code: Select all

global msg := "test"

f() {
	msgbox %msg%
}
main code:

Code: Select all

f()
but it works ok if we include library explicitly

main code:

Code: Select all

#Include <f>
f()
Why? Does automatic include attendant library's function call omit everything except function definition?

Re: Automatic inclusion doesn't work with globals

Posted: 30 Jul 2020, 19:18
by teadrinker
venaci wrote: Does automatic include attendant library's function call omit everything except function definition?
Yeah, exactly. You only include the function definition in that case.

Re: Automatic inclusion doesn't work with globals

Posted: 30 Jul 2020, 22:35
by lexikos
Wrong. The assignments are included but never executed, because the file is not included within the auto execute section (on v1).

I'm pretty sure enabling #Warn Unreachable would clarify this.

You can use static initializers on v1 (calling an initialization subroutine from the initializer) as an alternative.

Re: Automatic inclusion doesn't work with globals

Posted: 31 Jul 2020, 01:07
by teadrinker
lexikos wrote: Wrong. The assignments are included
If it's included, is there a way to get its value?

Re: Automatic inclusion doesn't work with globals

Posted: 31 Jul 2020, 01:46
by teadrinker
Found out the difference in behavior between compiled and uncompiled scripts. If I write in the library-script

Code: Select all

MsgBox, test
MyFunc() {
   MsgBox, % A_ThisFunc
}
and in the main script

Code: Select all

MyFunc()
then the line MsgBox, test won't be executed. However, if I compile my script, it will execute.
Now I see, that it's included. :)
But why is there this difference?

Re: Automatic inclusion doesn't work with globals

Posted: 31 Jul 2020, 02:05
by lexikos
AutoHotkey auto-includes the file after processing the main script, during the stage that it resolves function names to addresses. The physical end of the (main) script ends the auto-execute section (as documented), so any lines added after that are not part of the auto-execute section.

Ahk2Exe reads all include files and combines into one. It runs AutoHotkey.exe /iLib to determine which files should be "auto-included". It presumably does not add an "Exit" at the end of the main script prior to "auto-included" files, so it is possible for them to auto-execute. This could be considered a bug in the compiler.
teadrinker wrote:If it's included, is there a way to get its value?
Get whats value? The assignment hasn't been evaluated, so the variable has no value. If you know where the file is, you can read it and parse the assignment. But you are better off using #include <libname> in the auto-execute section instead. You could alternatively utilize a static initializer to have a function be called automatically, as I mentioned.

Re: Automatic inclusion doesn't work with globals

Posted: 31 Jul 2020, 08:18
by venaci
@Lexicos By static initializers you mean to have local static variables instead of globals?

Code: Select all

f() {
	static msg := "test"
}
This wouldn't be sufficient because despite my library have only one useful function (hence no need for explicit inclusion) but it have a few inner functions not meant to be used by user but necessary for its main function.
Unfortunately they need to share a few global variables holding configuration and passing them between functions as arguments would be inconvenient and would look bad.

Maybe this problem could be addressed by changing code structure but this would need some advice from more experienced programmers.

Re: Automatic inclusion doesn't work with globals

Posted: 31 Jul 2020, 09:22
by awel20
This is one example of a static initializer. The two functions fn1() and fn2() call the function Init() at run time. The two functions share a reference to the same object which allows sharing of information between the functions.

Code: Select all

MsgBox % fn1() "`n" fn2()

Init()
{
    static ConfigArray := ""
    if !(ConfigArray)
    {
        ConfigArray := {"Setting1": 1234, "Setting2": 2345, "LoadTime": A_Now, "TickCount": A_TickCount}
        ;...
    }
    return ConfigArray
}

fn1()
{
    static ConfigArray := Init()
    return ConfigArray.TickCount
}

fn2()
{
    static ConfigArray := Init()
    return ConfigArray.LoadTime
}

Re: Automatic inclusion doesn't work with globals

Posted: 01 Aug 2020, 04:45
by lexikos
My suggestion was just to use the static initializer to call a function at startup. The variable which you initialize does not need to be used in any way, and the function can do whatever you want, including assign global variables.

Re: Automatic inclusion doesn't work with globals

Posted: 01 Aug 2020, 16:38
by TAC109
lexikos wrote:
31 Jul 2020, 02:05
...
Ahk2Exe reads all include files and combines into one. It runs AutoHotkey.exe /iLib to determine which files should be "auto-included". It presumably does not add an "Exit" at the end of the main script prior to "auto-included" files, so it is possible for them to auto-execute. This could be considered a bug in the compiler.
This bug has been fixed in the latest Ahk2Exe source.