Static init functions (was: Goto Eof)

Propose new features and changes
ekipan
Posts: 11
Joined: 05 Aug 2014, 18:31

Static init functions (was: Goto Eof)

05 Aug 2014, 19:59

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?
Last edited by ekipan on 06 Aug 2014, 11:15, edited 2 times in total.
guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: Goto Eof

06 Aug 2014, 01:14

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

lexikos
Posts: 9625
Joined: 30 Sep 2013, 04:07
Contact:

Re: Goto Eof

06 Aug 2014, 03:20

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.
    */
}
ekipan
Posts: 11
Joined: 05 Aug 2014, 18:31

Re: Goto Eof

06 Aug 2014, 11:01

lexikos wrote:(code)
An excellent solution indeed. I've changed my scripts to use it and am satisfied with the result. I retract the feature request.

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() {
  ; ...
}
Seems like a much larger language change than the original proposal, and I'm not really too fussed about it, I'm satisfied with how it is now. Just putting this proposal forward for the sake of argument.
User avatar
joedf
Posts: 8978
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: Static init functions (was: Goto Eof)

06 Aug 2014, 18:34

@lexikos nice hack
Image Image Image Image Image
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]
lexikos
Posts: 9625
Joined: 30 Sep 2013, 04:07
Contact:

Re: Goto Eof

06 Aug 2014, 22:34

ekipan wrote:Though, it does still require a unique name among all files for each init function.
Doesn't the file need a unique path/name anyway?

Code: Select all

Static() {
  ; ...
}
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 x := 1, y := 2
Static {
  x := 1
  y := 2
}
It might be possible to allow local variables within the block (perhaps only explicit ones like local varname).
ekipan
Posts: 11
Joined: 05 Aug 2014, 18:31

Re: Goto Eof

07 Aug 2014, 00:14

lexikos wrote:Doesn't the file need a unique path/name anyway?
Yeah, I'm paranoid about names and namespaces. It's a weakness.
lexikos wrote:Perhaps since it is a language feature and would not have any parameters, the () should be omitted.
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:

Code: Select all

Static 
{
  ; ...
}
Is this a static initializer function or is it an assume static declaration followed by a block? The former can only be at top level and the latter only within a function, so I guess it isn't ambiguous, but maybe it's something to keep in mind.

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)
Personally I'd prefer a static initializer block to behave semantically exactly the same as your init_this_file() function.
guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: Goto Eof

07 Aug 2014, 01:00

Would such a static function effectively replace the auto-execute section? Or would they be used in tandem?
Personally I'd prefer a static initializer block to behave semantically exactly the same as your init_this_file() function.
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'

But how would it work? Would all included files have this same "static" func name within all of them? It seems Go allows this:
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.
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?

ekipan
Posts: 11
Joined: 05 Aug 2014, 18:31

Re: Goto Eof

07 Aug 2014, 01:14

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.
I'm also not a fan of the random syntax block, I'd rather see a 'reserved' function name static
Static is already a reserved word. Look again at lexicos's init_this_file() function. That's how it would behave.

http://ahkscript.org/docs/Functions.htm#static
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.
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().
Last edited by ekipan on 07 Aug 2014, 01:24, edited 1 time in total.
guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: Goto Eof

07 Aug 2014, 01:20

ekipan wrote:Why would adding static inits make auto-exec go away? That would break all scripts everywhere. Unthinkable.
My bad, I thought this was a v2 request, where v2 will break compatibilty anyway.
I'm also not a fan of the random syntax block, I'd rather see a 'reserved' function name static
Static is already a reserved word.
http://ahkscript.org/docs/Functions.htm#static
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'

Most important question is "How necessary is this?" which you ignored

ekipan
Posts: 11
Joined: 05 Aug 2014, 18:31

Re: Static init functions (was: Goto Eof)

07 Aug 2014, 01:37

Code: Select all

Static() {
  Msgbox asdf
}
Static()
Hmm, I just tested this in v1.1.15, and it showed a message box. Surprising. I was expecting a syntax error or something. Without the parens it is an error though, so it would be completely safe to extend the syntax that way. It's also got precedent: it looks exactly the same in Java.

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.
lexikos
Posts: 9625
Joined: 30 Sep 2013, 04:07
Contact:

Re: Goto Eof

07 Aug 2014, 02:02

ekipan wrote:Is this a static initializer function or is it an assume static declaration followed by a block?
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.

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()
{
}
There's no ambiguity: it's a function definition. Inside a function, it's an illegal function definition.

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)
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.
but a static block is top-level
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).
Personally I'd prefer a static initializer block to behave semantically exactly the same as your init_this_file() function.
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.
guest3456 wrote:I'd rather see a 'special' function name static() or "init", that if defined with no args, becomes this 'initializer'
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 ().
Would all included files have this same "static" func name within all of them?
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.
guest3456 wrote:My bad, I thought this was a v2 request, where v2 will break compatibilty anyway.
It wasn't for a specific version, was it? More importantly, there's simply no reason to remove the auto-execute section.
ekipan wrote:... the request is effectively down to not requiring names for all of one's initializer functions.
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
Posts: 11
Joined: 05 Aug 2014, 18:31

Re: Static init functions (was: Goto Eof)

08 Aug 2014, 20:48

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:

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)
}
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.

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")

Return to “Wish List”

Who is online

Users browsing this forum: No registered users and 11 guests