Scenario: Script with both hotkeys and autoexecute code. You want it runnable either on its own or included in another script.
Problem: Encountering a hotkey will terminate the autoexecute.
Solution 1: Gosub in parent script, label before the #Include, Return at end of child script autoexecute. Cons: Both scripts need to be aware of this mechanism and written accordingly. Requires an otherwise uneccessary label name. I've seen this solution recommended before, though.
Solution 2: #Include within parent script autoexecute, Goto at end of child script autoexecute, label at end of child script file. Unlike solution 1 only the child script needs to be bothered with the details, though like solution 1 it still needs the label name. Others have come up with this (1). It's even built into the Windows batch script: "goto :eof" (though there it's more to act as a return statement for its subroutines).
Feature Request: I would like syntactic support in Autohotkey for solution 2. Namely, I'd like for the label name to not be neccessary; for there to be a command, as in batch script, for "Goto the end of this file."
This could take several forms, perhaps a new command "GotoEof" (1) or maybe even "ExitFile" (2) or something. Or take a cue from batch and add a special form to the Goto command: "Goto, Eof" (3).
Back-compat considerations: introducing a new command (1) (2) means a new reserved word. Changing the meaning of existing syntax (3) seems somewhat less violent. Interactions: If a label "Eof" exists, it could go there instead of doing the special behavior (3a). Or "Eof" could be forbidden as a label: a load-time error (3b). Or a compromise: 3a by default, 3b if a #Warn directive is used (3c). 3a is more compatible, but I like 3b better so that the meaning of my script won't change based on where it's included.
I think this would be a worthwhile change, especially for its relative smallness (semantically. I make no assertions on implementation effort). Thoughts?
Static init functions (was: Goto Eof)
Static init functions (was: Goto Eof)
Last edited by ekipan on 06 Aug 2014, 11:15, edited 2 times in total.
Re: Goto Eof
Its just poor design to include a separate script with another autoexecute section. You shouldn't even try to do it after reading the #include docs. If your included script has hotkeys only, then you can put the #include lines at the END of the parent script, which was done in some of majkinetor's old scripts
Re: Goto Eof
Code: Select all
init_this_file() {
static _ := init_this_file()
/*
This function is called automatically when the script starts,
regardless of where it is #included.
*/
}
Re: Goto Eof
An excellent solution indeed. I've changed my scripts to use it and am satisfied with the result. I retract the feature request.lexikos wrote:(code)
Though, it does still require a unique name among all files for each init function. I suppose I could repurpose this thread to request language support for static init functions.
Maybe it would look something like this:
Code: Select all
Static() {
; ...
}
Re: Static init functions (was: Goto Eof)
@lexikos nice hack
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]
Re: Goto Eof
Doesn't the file need a unique path/name anyway?ekipan wrote:Though, it does still require a unique name among all files for each init function.
Thank you for the suggestion. Perhaps since it is a language feature and would not have any parameters, the () should be omitted. So we would have:Code: Select all
Static() { ; ... }
Code: Select all
Static x := 1, y := 2
Static {
x := 1
y := 2
}
Re: Goto Eof
Yeah, I'm paranoid about names and namespaces. It's a weakness.lexikos wrote:Doesn't the file need a unique path/name anyway?
I came to the same conclusion after posting. Indeed Java has exactly this syntax for its static initializers (modulo keyword case sensitivity). Go has its own analogous init() functions as well. Consider this though:lexikos wrote:Perhaps since it is a language feature and would not have any parameters, the () should be omitted.
Code: Select all
Static
{
; ...
}
I don't understand this, though:
Code: Select all
Static x := 1, y := 2
; ^^^ static variables only make sense inside a function
Static { ; <-- but a static block is top-level, acting as its own function
x := 1 ; <-- thus it would make sense for these to be local unless
y := 2 ; explicitly declared global or static (usually static wouldn't
} ; even make sense: you can't call a static initializer again)
Re: Goto Eof
Would such a static function effectively replace the auto-execute section? Or would they be used in tandem?
But how would it work? Would all included files have this same "static" func name within all of them? It seems Go allows this:
I'm also not a fan of the random syntax block, same with the new get/set property syntax but thats a little different being inside a class definition. I'd rather see a 'special' function name static() or "init", that if defined with no args, becomes this 'initializer'Personally I'd prefer a static initializer block to behave semantically exactly the same as your init_this_file() function.
But how would it work? Would all included files have this same "static" func name within all of them? It seems Go allows this:
But how necessary is this? Shouldn't end users take care not to #include files with their own autoexec section? Shouldn't #included files be mostly library type files with functions? Is it that difficult to copy and paste any hotkey definitions?http://golang.org/doc/effective_go.html#init wrote: Variables may also be initialized using functions named init declared in the package block, with no arguments and no result parameters.
Multiple such functions may be defined, even within a single source file. The init identifier is not declared and thus init functions cannot be referred to from anywhere in a program.
A package with no imports is initialized by assigning initial values to all its package-level variables followed by calling all init functions in the order they appear in the source, possibly in multiple files, as presented to the compiler.
Re: Goto Eof
Why would adding static inits make auto-exec go away? That would break all scripts everywhere. Unthinkable. Static inits are just a better alternative because they are guaranteed to be executed regardless of a script's include environment.
http://ahkscript.org/docs/Functions.htm#static
Static is already a reserved word. Look again at lexicos's init_this_file() function. That's how it would behave.I'm also not a fan of the random syntax block, I'd rather see a 'reserved' function name static
http://ahkscript.org/docs/Functions.htm#static
Edit: And yes, a script would be permitted to have any number of static initializers, just like Java's static initializers and Go's init().Each static variable is initialized only once (before the script begins executing). (...) Static var := expression is supported. All such expressions are evaluated immediately before the script's auto-execute section in the order they are encountered in the script.
Last edited by ekipan on 07 Aug 2014, 01:24, edited 1 time in total.
Re: Goto Eof
My bad, I thought this was a v2 request, where v2 will break compatibilty anyway.ekipan wrote:Why would adding static inits make auto-exec go away? That would break all scripts everywhere. Unthinkable.
lol thanks pal. I'm well aware that static is a reserved word. Is it a reserved function name? No. Anyway I had edited my post before you replied and changed 'reserved' to 'special'Static is already a reserved word.I'm also not a fan of the random syntax block, I'd rather see a 'reserved' function name static
http://ahkscript.org/docs/Functions.htm#static
Most important question is "How necessary is this?" which you ignored
Re: Static init functions (was: Goto Eof)
Code: Select all
Static() {
Msgbox asdf
}
Static()
I ignored the question about necessity because it's not a constructive question. I have a use case in mind, this pattern is already possible in the language as-is, and so the request is effectively down to not requiring names for all of one's initializer functions.
Re: Goto Eof
Right now it's either invalid or an assume static declaration followed by a redundant block. There's no purpose in putting the block there.ekipan wrote:Is this a static initializer function or is it an assume static declaration followed by a block?
If this is implemented (in v2), it would be a static initialization block. It would be assume-static if inside a function, or assume-global otherwise. (At least, that's how I imagine it working.)
Consider the code below: is it a function call followed by a block, or is it a function definition?
Code: Select all
Function()
{
}
That depends on what meaning you assign to it. If static was required to declare static variables inside the block, it would make less sense for them to be local to the outer function. It would also look strangely redundant. In that case, something like auto { } might make more sense.Code: Select all
Static { ; <-- but a static block is top-level, acting as its own function x := 1 ; <-- thus it would make sense for these to be local unless y := 2 ; explicitly declared global or static (usually static wouldn't } ; even make sense: you can't call a static initializer again)
My implication was that it wouldn't necessarily be top-level. Static would optionally accept a block of initialization code instead of a list of variable names and initializers. Both types of static declarations could also be valid outside functions (for auto-initialization purposes).but a static block is top-level
I think you're giving it the wrong meaning (and perhaps so was I). We use the static keyword because the variable's value is unchanging (i.e. static) between function calls. The initializer expressions are evaluated at load time automatically because that's the most useful behaviour, but it would be semantically valid for them to be evaluated the first time the function is called.Personally I'd prefer a static initializer block to behave semantically exactly the same as your init_this_file() function.
You cannot define two functions with the same name. Why should an exception be made for Static()? It's effectively then not a function definition, so may as well make it distinct by not requiring ().guest3456 wrote:I'd rather see a 'special' function name static() or "init", that if defined with no args, becomes this 'initializer'
You want end-users to take care about particular implementation details of a module they are using? Modules are meant to be re-used, to save time and effort.Would all included files have this same "static" func name within all of them?
It wasn't for a specific version, was it? More importantly, there's simply no reason to remove the auto-execute section.guest3456 wrote:My bad, I thought this was a v2 request, where v2 will break compatibilty anyway.
And of course not requiring the additional dummy declaration and assignment: static _ := the_function(). Features like this make it easier for people to write reusable code, which can then benefit everyone, including average users who mightn't be good with technical details like static initializers. (This isn't intended as a direct answer to guest3456's question. My posts have been mostly hypothetical.)ekipan wrote:... the request is effectively down to not requiring names for all of one's initializer functions.
Re: Static init functions (was: Goto Eof)
Not content with Lexikos's merely clever code, I have taken it to the downright obtuse. His remark that even the file needs a unique name sparked a thought: if the initializer function was the same name as the file, I wouldn't care so much about the used up name, plus it could be implicitly included by calling the init function directly.
Except that would cause it to execute twice: once by the static assignment when the file is loaded, then again because the function was invoked directly. How could I solve this with as few lines of code as possible? I came up with this:
So yeah.
(_:=1) / Foo() first _ is assigned a 1.
1 / Foo() then Foo() is called. It does its job then returns nothing.
1 / "" division by zero is undefined, which gives just:
"" which is then finally assigned to _.
Subsequent calls are aborted via IfNotEqual.
Works well! It's also completely terrible.
Except that would cause it to execute twice: once by the static assignment when the file is loaded, then again because the function was invoked directly. How could I solve this with as few lines of code as possible? I came up with this:
Code: Select all
; File Foo.ahk
Foo() {
Static _ := (_:=1) / Foo() ; this function is guaranteed to be called
IfNotEqual, _, 1, Return ; and will execute exactly once.
; ... (initialize the Foo module)
}
(_:=1) / Foo() first _ is assigned a 1.
1 / Foo() then Foo() is called. It does its job then returns nothing.
1 / "" division by zero is undefined, which gives just:
"" which is then finally assigned to _.
Subsequent calls are aborted via IfNotEqual.
Works well! It's also completely terrible.
Code: Select all
Foo("toplevel 1")
Foo("toplevel 2")
Bar() {
Static _ := Foo("an earlier function")
}
Foo(callsite) {
MsgBox called from %callsite%
Static _ := (_:=1) / Foo("itself")
IfNotEqual, _, 1, Return
MsgBox executed
}
Foo("toplevel 3")
Who is online
Users browsing this forum: No registered users and 11 guests