Obsolete test build - Functions and Objects as Labels (etc.)

Community news and information about new or upcoming versions of AutoHotkey
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Obsolete test build - Functions and Objects as Labels (etc.)

04 Jan 2015, 07:07

OBSOLETE: Get v1.1.20.00 instead.

I have uploaded a test build with some long-awaited experimental features, based on v1.1.19.

Functions and Objects as Labels
  • Hotkey, SetTimer, Gui g-labels, Menu and OnExit have been retro-fitted to accept functions and objects.
  • Functions can be defined instead of labels for Gui events like GuiClose (and 2GuiClose, etc.).
  • OnClipboardChange is unaffected due to rarity of need and potential conflict with the OnClipboardChange() function in AutoHotkey v2.
If a name is given and a label by that name exists, it is used. Otherwise, functions with no mandatory parameters can be specified by name. Objects can only be passed via a single %variable% deref, due to certain limitations of commands in v1. So for example:

Code: Select all

Gui Add, Button, w75        , Implied
Gui Add, Button, w75 gButton, Explicit
Gui Add, Button, w75        , Bound object
fn := bind("Button", 42)  ; Bind parameters to a function.
GuiControl +g, Bound object, %fn%

ButtonImplied() {  ; Implicitly used by Button "TEST".
    MsgBox %A_GuiControl%
}
Button(s:="") {
    MsgBox %A_GuiControl%`n%s%
}

/*
GuiClose:  ; This line doesn't stop execution, so script will exit.
ExitApp
*/
GuiClose() {
    ExitApp
}

Gui Show  ; Still in the auto-execute section.
To pass an object to Hotkey, SetTimer, Menu and OnExit, just pass a single %variable% deref instead of a label name:

Code: Select all

fn := bind("Timer", 1)
SetTimer %fn%, -1000
SetTimer %fn%, -2000  ; Change interval of existing timer
fn := bind("Timer", 2)
SetTimer %fn%, -1000  ; Create separate timer

Sleep 3000
; Result: Timer 2, followed by Timer 1.

Timer(n) {
    ToolTip Timer %n%
    Sleep 950
    ToolTip
}
bind() is defined as follows:

Code: Select all

bind(fn, args*) {  ; bind v1.2
    try bound := fn.bind(args*)  ; Func.Bind() not yet implemented.
    return bound ? bound : new BoundFunc(fn, args*)
}

class BoundFunc {
    __New(fn, args*) {
        this.fn := IsObject(fn) ? fn : Func(fn)
        this.args := args
    }
    __Call(callee, args*) {
        if (callee = "" || callee = "call" || IsObject(callee)) {  ; IsObject allows use as a method.
            fn := this.fn, args.Insert(1, this.args*)
            return %fn%(args*)
        }
    }
}
%Fn%() syntax still calls Fn[""]() for backward-compatibility, but this is changing in v2 to use Fn.Call() (also, v1.1.19 adds Func.Call()), so this new feature uses Call(), which is more convenient to define. For example:

Code: Select all

mi := new MenuItem(1)
Menu M, Add, Hello, %mi%
mi := new MenuItem("A")
Menu M, Add, World, %mi%
Menu M, Show

class MenuItem {
    __New(name) {
        this.name := name
    }
    Call() {
        MsgBox % "Called menu item " this.name
    }
}
Internally, Fn.call() is used rather than Fn.Call(), for compatibility with JavaScript Function objects.

For Gui buttons, you can define ButtonOK() as you would define a label, or you can use +gFuncName. To use an object, you need to use GuiControl with the third parameter being a single %variable% deref (the object):

Code: Select all

GuiControl +g, Button1, %fn%
Note that this script won't run on older versions of AutoHotkey, which require the last parameter to be blank for the +Options sub-command. You can work around this (if you really want to) by putting a variable deref in the sub-command parameter, like GuiControl +g%empty%, ....

For hotkeys, Suspend Permit works with labels and functions. It cannot work with other objects, as it is not known which line (if any) will be executed first when the object is called.

Added on 2015-01-13: Hotkey functions, as demonstrated below.

Code: Select all

^a::
^b::
    pressing_ctrl_a_or_b_calls_this_function() {
        MsgBox %A_ThisHotkey%
    }
Added on 2015-01-13: SetTimer %Object%, Delete deletes the timer. All kinds of timers can be deleted, but it's only really needed for objects. Deleting a timer frees its reference to the object and a small amount of memory. If you turn a timer Off and back On, it retains its Period and Priority, so SetTimer %Object%, Off cannot release the object.

Localized Key Characters

This affects GetKeyName, Hotkey Gui controls, A_PriorKey, KeyHistory and Input (when ErrorLevel is EndKey:).

In prior releases, the VK codes 'A' (vk41) to 'Z' (vk5A) were always named using their ASCII counterparts (at least on systems with US keyboard as the default, even if some other layout is in use). This is apparently due to some quirky behaviour of MapVirtualKey. All other keys, including those that produce letters, were already converted to the appropriate character depending on the script's current keyboard layout.

So for example, if I switch from US to Russian layout and press Ctrl+й, the Hotkey control produces ^Q even though the Hotkey command refuses to register that hotkey (because Q doesn't exist in the Russian layout).

This change may break some scripts. It may also fix some scripts. Note that for backward-compatibility, the Input command's ErrorLevel returns EndKey:A rather than EndKey:a even though non-ASCII letters are returned in lower-case. Also note that while ^q:: and ^Q:: perform identically, ^Q is actually equivalent to ^+q when used with Send.

The Input command has a new option E, which causes single-character EndKeys to be handled by character rather than by VK or SC. This allows Input to adapt to the keyboard layout of the active window when multiple layouts are in use. It also prevents the end key from being triggered if that character isn't actually typed (such as if the Alt or Ctrl keys are held down).

Other Changes

There are some other changes in later updates. Look for "Update" in later posts.

Download
User avatar
fincs
Posts: 527
Joined: 30 Sep 2013, 14:17
Location: Seville, Spain
Contact:

Re: New test build - Functions and Objects as Labels (and m

04 Jan 2015, 09:13

Functions and Objects as Labels

Nice. I think this is a pretty important step in making certain parts of the AutoHotkey feature set more flexible and easier to use. Ideally, However, I have a few concerns:
lexikos wrote:If a name is given and a label by that name exists, it is used. Otherwise, functions with no mandatory parameters can be specified by name.
This is fine, especially for backwards compatibility purposes. However IMO in v2, functions should have more priority than subroutines.
lexikos wrote:Functions can be defined instead of labels for Gui events like GuiClose (and 2GuiClose, etc.).
Isn't a name that starts with a digit supposed to be illegal in function names? (I assume you meant a non-numeric Gui name like MyGui).
lexikos wrote:(...) you can use +gFuncName.
Why the plus sign? If it's for not breaking backwards compatibility, isn't that already covered by giving more priority to subroutines?
lexikos wrote:as timers cannot be deleted, each time you register a new timer more memory will be allocated. Even if you turn off the timer, neither the timer nor the object will be freed. You can't delete hotkeys either, but you can replace the object with a label or function, and the object will be released.
This is bad. IMO it needs to be fixed before merging to the main branch.

Finally, I am wondering how this would affect my Gui redesign proposal, or any hypothetical Menu redesign proposal. The event system I implemented accepts (prefixed) function names, or method names used to invoke a certain object.
fincs
Windows 11 Pro (Version 22H2) | AMD Ryzen 7 3700X with 32 GB of RAM | AutoHotkey v2.0.0 + v1.1.36.02
Get SciTE4AutoHotkey v3.1.0 - [My project list]
User avatar
joedf
Posts: 8940
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: New test build - Functions and Objects as Labels (and m

04 Jan 2015, 11:16

Functions and Objects as Labels
+1 :+1:
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]
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: New test build - Functions and Objects as Labels (and m

04 Jan 2015, 11:58

joedf wrote:
Functions and Objects as Labels
+1 :+1:
def +1 for the effort

However this seems like quite a hack, having to use bind() and a BoundFuncObj. Then again, I don't know the internals of the lang so maybe the easy/intuitive/most requested way that you would expect to use a func is just not possible or requires too much of a rewrite.

This

Code: Select all

Hotkey, F1, myHotkeyFunc
SetTimer, myTimerFunc, 1000

myHotkeyFunc()
{
}

myTimerFunc()
{
}
is what you'd expect to do, rather than having to use all the extra code that very few people will understand

User avatar
fincs
Posts: 527
Joined: 30 Sep 2013, 14:17
Location: Seville, Spain
Contact:

Re: New test build - Functions and Objects as Labels (and m

04 Jan 2015, 12:57

guest3456 wrote:This is what you'd expect to do, rather than having to use all the extra code that very few people will understand
The extra code is only necessary when you want to bind parameters to the function. The code you posted is already working with the test build.
fincs
Windows 11 Pro (Version 22H2) | AMD Ryzen 7 3700X with 32 GB of RAM | AutoHotkey v2.0.0 + v1.1.36.02
Get SciTE4AutoHotkey v3.1.0 - [My project list]
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: New test build - Functions and Objects as Labels (and m

04 Jan 2015, 16:51

fincs wrote:Isn't a name that starts with a digit supposed to be illegal in function names?
Not in v1.
Why the plus sign?
Why not the plus sign?

Plus signs are optional when creating a control, but the first option passed to GuiControl must always have + or -. In earlier releases, -gLabelName was the same as +gLabelName. That's not the case any more (who would do such a thing?) but +g or +g%empty% is still the same as -g (i.e. set the label to empty).
This is bad. IMO it needs to be fixed before merging to the main branch.
The problem is that the Priority setting needs to remain even after turning off the timer.
guest3456 wrote:However this seems like quite a hack, having to use bind() and a BoundFuncObj.
Things aren't as they seem. I didn't write an example for the simple case, because it's simple. Also, using a function with no args directly in place of a label is a mere convenience, whereas using an object to bind parameters to a function call adds a lot of flexibility.
User avatar
joedf
Posts: 8940
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: New test build - Functions and Objects as Labels (and m

04 Jan 2015, 17:19

Adding on to the "simple" usage, I imagine that the Function will have priority over the label with the same specified name. Correct?
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]
User avatar
Nextron
Posts: 1391
Joined: 01 Oct 2013, 08:23
Location: Netherlands OS: Win10 AHK: Unicode x32

Re: New test build - Functions and Objects as Labels (and m

04 Jan 2015, 17:40

That's not how I read it:
If a name is given and a label by that name exists, it is used. Otherwise, functions with no mandatory parameters can be specified by name.
Like fincs already mentioned, for backward compatibility this order of priority seems mandatory.
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: New test build - Functions and Objects as Labels (and m

05 Jan 2015, 00:32

fincs wrote:
guest3456 wrote:This is what you'd expect to do, rather than having to use all the extra code that very few people will understand
The extra code is only necessary when you want to bind parameters to the function. The code you posted is already working with the test build.
lexikos wrote:
guest3456 wrote:However this seems like quite a hack, having to use bind() and a BoundFuncObj.
Things aren't as they seem. I didn't write an example for the simple case, because it's simple.
My apologies, I missed this. Forget my post.
lexikos wrote: Also, using a function with no args directly in place of a label is a mere convenience
I've wanted it to simply avoid global scope

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

Re: New test build - Functions and Objects as Labels (and m

05 Jan 2015, 02:45

You can do that by writing a label which calls a function. It's only less convenient, not less effective.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: New test build - Functions and Objects as Labels (and m

05 Jan 2015, 06:30

It can't get this treatment; OnMessage already calls functions, not labels, and has parameters to pass. However, enhancing it to allow calling objects instead of functions is on my list along with adding a built-in Func.Bind() method.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: New test build - Functions and Objects as Labels (and m

05 Jan 2015, 06:36

I know, I was just being pedantic.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: New test build - Functions and Objects as Labels (and m

05 Jan 2015, 06:40

Actually, I was also half-explaining why the code added in this new test build couldn't be applied to OnMessage (otherwise I would have done it already). But I forgot that shortly after posting.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: New test build - Functions and Objects as Labels (and m

06 Jan 2015, 12:22

Just a heads up - Bind() does not like being a class method.
Keep it as a global func, people.

Lex - I take it Bind() is gonna be a built-in, so no point making it a class method anyway?
User avatar
joedf
Posts: 8940
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: New test build - Functions and Objects as Labels (and m

06 Jan 2015, 12:27

Yes, would be cool and much more practical to have bind() built in. :)
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]
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
Contact:

Re: New test build - Functions and Objects as Labels (and m

06 Jan 2015, 14:14

evilC wrote:Just a heads up - Bind() does not like being a class method.
Keep it as a global func, people.
IMO, bind() as a Func object method ensures that it is only applied to functions(as it should be). You can simply do BoundFunc := Func(FunctionName).Bind(args*)

Return to “Announcements”

Who is online

Users browsing this forum: No registered users and 29 guests