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:

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

11 Feb 2015, 06:24

Update - v1.1.19.03-22+g2609ddd

Changed OnMessage to register new monitors to be called last if MaxThreads is negative. The parameter's absolute value is used for the actual maximum thread count. For example:

Code: Select all

OnMessage(0x8000, Func("First"))
OnMessage(0x8000, Func("Second"), -1) ; -1 gives it a lower priority than any previously registered monitors.
DetectHiddenWindows On
SendMessage 0x8000,,,, ahk_id %A_ScriptHwnd%
ExitApp

First() {
    MsgBox First
}
Second() {
    MsgBox Second
}
Input command:
  • Single-character end keys (not in braces) are now handled by character, not by VK. If you type that character, Input is ended with ErrorLevel = EndKey:c (where c is the character). End characters respect the active window's keyboard layout and modifier key state (just like the output and match list). The 'C' (case sensitive) option is also respected.
  • Keys in braces, like {a}, are still handled by VK as in the stable branch.
For instance,
  • a produces EndKey:a or EndKey:A depending on what was typed, and is not triggered if Alt or Ctrl are held down. If the C option is used, typing A does not end input (unless A is also listed as a separate end key).
  • {A} produces EndKey:A and is triggered regardless of the Ctrl, Alt or Shift keys or the C option.
  • й produces EndKey:й or EndKey:Й instead of EndKey:Q (as in the stable branch), and respects the active window's keyboard layout, the modifier key state and C option. It also works regardless of the script's keyboard layout, and is never triggered by typing Q.
  • {й} produces EndKey:й instead of EndKey:Q, but still requires that the script's keyboard layout contains й and can be triggered by typing Q (when they have the same VK code, and multiple keyboard layouts are in use).
  • " does not trigger if the Alt or Ctrl keys are held down, whereas {"} acts as before (it ignores the Alt and Ctrl keys but requires the Shift key).
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

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

11 Feb 2015, 07:48

lexikos wrote:Update - v1.1.19.03-22+g2609ddd

Changed OnMessage to register new monitors to be called last if MaxThreads is negative. The parameter's absolute value is used for the actual maximum thread count. For example:

Code: Select all

OnMessage(0x8000, Func("First"))
OnMessage(0x8000, Func("Second"), -1) ; -1 puts it before any previously registered monitors.
DetectHiddenWindows On
SendMessage 0x8000,,,, ahk_id %A_ScriptHwnd%
ExitApp

First() {
    MsgBox First
}
Second() {
    MsgBox Second
}
The comment in that code ; -1 puts it before any previously registered monitors confused me a little.
I assume what you mean is that since, by default (omitted or positive MaxThreads), OnMessage is LIFO - by using a negative value, you put the item "before" any other items, ie as if it were first in and thus will be last out? So you are actually setting it to fire after other messages, but it is before the other items in the LIFO queue?

I really would prefer FIFO as the default, it's just more logical IMHO.
Default behavior should mean that code executed first gets the message first - it's pretty logical to initialize a library before you start using it, at the start of your code.
This would reduce the burden of knowledge on people using libraries where their code also monitors a message that the library monitors - if they do not know to always use -1 (the "non-default" setting) in their code, then they will always be getting messages before their libraries.

Anyone else agree or am I on an Island here / missing something? Is it too late to change?
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

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

11 Feb 2015, 16:52

The comment in that code ; -1 puts it before any previously registered monitors confused me a little.
I've changed the wording. The original wording was referring to the way they're stored internally, which is irrelevant to you because you don't know how that relates to the order they're called in.
Default behavior should mean that code executed first gets the message first
Why?
This would reduce the burden of knowledge on people using libraries where their code also monitors a message that the library monitors
I disagree. Which one needs to be called first and why? It depends entirely on what the script and the library are doing. The user needs to know what they're doing either way, since they could initialize the library before or after their own code.
  • Often the order that the libraries are initialized in isn't explicitly defined by the user, but instead inferred by the order that function calls are physically encountered in the script (e.g. auto-includes), and/or how the library is included.
  • If they're each monitoring for a different thing, like notifications for different controls, the order doesn't matter.
  • If the monitors aren't designed to be compatible in the first place, they won't work regardless of order.
  • The old behaviour was to call the most recently registered monitor first (and other monitors never).
  • Keyboard/mouse hooks work this way; the most recently-installed hook is called first.
  • Function calls and AutoHotkey's quasi-threads aren't FIFO. If the thread gets interrupted by a new event occurring, the subroutine for the new event must complete before the previous thread resumes.
  • If you register a monitor temporarily with low priority, it might never be called at all if some other monitor was already registered; hence high priority by default. For example, I have a script which uses messages for IPC. It uses OnMessage to temporarily register a WM_COPYDATA handler to receive the result, something like:

    Code: Select all

    onCopyData := OnMessage(0x4a, "ReceiveResponse")
    SendCommand("Command", hwnd)
    ;... ReceiveResponse stores the result in R ...
    OnMessage(0x4a, onCopyData)
    return R
    ...which could be written as:

    Code: Select all

    OnMessage(0x4a, Func("ReceiveResponse"), 1)
    SendCommand("Command", hwnd)
    ;... ReceiveResponse stores the result in R ...
    OnMessage(0x4a, Func("ReceiveResponse"), 0)
    return R
It's not too late to change, but I would need a good reason.
I really would prefer FIFO as the default, it's just more logical IMHO.
I think you're confusing logic with intuition. Or maybe you just haven't explained your logic.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

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

11 Feb 2015, 17:44

Something can be illogical without being anything inherently to do with logic, surely?
I was saying that it behaved in an unexpected, or illogical, or un-intuitive manner.

As an example, which code snippet immediately makes how it all works more obvious?
The objective is to have the code output information in the same order as it appears in the source (To make understanding it easier) and using only defaults (to keep the syntax as simple as possible).

Code: Select all

OnMessage(0x8000, Func("Third"))
OnMessage(0x8000, Func("Second"))
OnMessage(0x8000, Func("First"))

[...]

First() {
    MsgBox 1
}
Second() {
    MsgBox 2
}
Third() {
    MsgBox 3
}
Or

Code: Select all

OnMessage(0x8000, Func("First"))
OnMessage(0x8000, Func("Second"))
OnMessage(0x8000, Func("Third"))

[...]

First() {
    MsgBox 1
}
Second() {
    MsgBox 2
}
Third() {
    MsgBox 3
}
The second one, as less brain processing is required (You don't have to spot the swap in order, just notice each OnMessage matches a function). If you were documenting it, you would not have to add any extra words to explain the difference in the order between the flow of execution and the order the output happens.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

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

11 Feb 2015, 20:25

Both examples are equally obvious and contrived, IMO.
I was saying that it behaved in an unexpected, or illogical, or un-intuitive manner.
One might infer that from your post, but you did not actually say it as far as I can see.
If you were documenting it, you would not have to add any extra words to explain the difference in the order between the flow of execution and the order the output happens.
The difference between the two options is just a few words, and both options must be documented regardless of which is the default.
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

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

12 Feb 2015, 14:22

I think the function should be called in same order as it is registered.

In my view it is more likely that library functions (included automatically or manually) call OnMessage statically and register first.

Currently it is not possible for a library to make sure that its function gets called first, so user needs to make sure his OnMessage is registered before lib to do so.
I also think that user function will more likely return true than a library function.

So for example here OnMessage(0x9999,Func("fun")) would need to be registered statically before OnMessage(0x9999,Func("lib")) and that shouldn't be default behaviour in my view.
I think this code should run both functions by default.

Code: Select all

OnMessage(0x9999,Func("fun"))
DllCall("SendMessage","PTR",A_ScriptHwnd,"UInt",0x9999,"PTR",1,"PTR",0)
Return
fun(wParam,lParam){
    MsgBox % A_ThisFunc
    return 1 ; currently this avoids lib call, so only fun is called
}
lib(wParam,lParam){
    static init:=OnMessage(0x9999,Func("lib"))
    MsgBox % A_ThisFunc
}
EDIT:
removed useless var declaration and #Persistent.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

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

14 Feb 2015, 21:37

Update - v1.1.19.03-28+gc7055e7

Reversed the order that message monitors are called in.

Added E option to Input command to opt-in to the new end-char mode. By default with keyboard layouts where keys A-Z are mapped to the characters A-Z, the Input command should behave the same as in previous stable releases. With the E option, {x} is now interpreted the same as x; i.e. as a character. This allows {{} and {}} to be handled by character rather than by VK. {vkNN} and other multiple-character key names are handled by VK (or SC) regardless of the E option.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

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

15 Feb 2015, 01:22

Ooh I will have to have a play with that E option.

And of course you know I am gonna be happy to have FIFO messages :)

BTW, any rough idea on when this stuff will make it into release? When this branch gets merged, will that mean v2 gets these features too?
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

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

15 Feb 2015, 04:14

When it's finished.
  • Some of the callbacks should have parameters. In particular, some GUI events use ErrorLevel to pass a value, which is error-prone since ErrorLevel gets overwritten easily. Passing A_GuiEvent, A_EventInfo and ErrorLevel as parameters also allows the user to give them more meaningful names.
  • I will probably change OnExit to allow multiple handlers as with OnMessage. I am considering reverting the OnExit command and adding an OnExit() function for the new features. The v2 behaviour of passing A_ExitReason as a parameter and exiting by default (if the function doesn't return true) should also be implemented.
  • Func.Bind() is mostly done, but the bound function can only be called (not interrogated for parameter count, etc.). It will probably stay that way. I'm considering whether it's useful enough to also have Object.Bind() doing exactly the same thing (for user-defined function objects), or just Bind(Obj, Params), since it's trivial for the binding code/bound object to support any kind of callable object.
That's just the "callable" branch. Depending on how long it takes, the other changes (including several not in the test build) might get released ahead of that.

Everything that makes it into the v1 branch eventually gets merged into v2, if it didn't come from v2. I don't want to waste my time developing features that will be (or are already) obsolete in v2.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

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

15 Feb 2015, 06:17

The main thing I am really waiting for is to be able to compile exes with these test builds.

I tried compiling AHK myself, but VS was throwing errors I didn't understand.

Any chance you could up a copy of the BIN files so I can compile some demos of this new stuff I have been working on?
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

15 Feb 2015, 08:22

What are the errors?
Do you have VS 2010? WinSDK 7.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]
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

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

15 Feb 2015, 09:52

I have VS 2012.
No, I did not have WinSDK 7.1 installed.

I have now though - had some problems getting it installed, the page here was invaluable: http://ctrlf5.net/?p=184

I then had the error:
Warning 1 warning LNK4010: invalid subsystem version number 5; default subsystem version assumed D:\Temp\ahk\test builds\AutoHotkey_L-edge\LINK AutoHotkeyx
Error 2 error LNK2026: module unsafe for SAFESEH image. D:\Temp\ahk\test builds\AutoHotkey_L-edge\win2kcompat.obj AutoHotkeyx
Error 3 error LNK1281: Unable to generate SAFESEH image. D:\Temp\ahk\test builds\AutoHotkey_L-edge\bin\Win32w_debug\AutoHotkey.exe 1 1 AutoHotkeyx
I was able to set /SAFESEH:NO and it built.
However, no .bin file

[Edit] All good, now able to compile scripts to EXE using a test build :)

For those wanting to compile EXEs with v1.1.19.03-28+gc7055e7, a U32 BIN file can be found HERE
Last edited by evilC on 15 Feb 2015, 11:10, edited 3 times in total.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

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

22 Feb 2015, 17:10

I discovered by accident that my (work in progress) built-in implementation of a bound function can be applied more generally to bind a method name to an object, without requiring extra code. It would actually require a little more code to bind only to "Call". So the possible ways it could work are:
  • Usage fn := ObjBind(fn, args*) or fn := fn.bind(args*)
    • Call fn.Call(args*).
    • Call %fn%(args*), using an internal "call the object itself" flag. Currently this would have the effect that Func objects would treat it like fn.Call(args*) while other objects would treat it like fn[args.Remove(1)](args*). (Inconsistent.)
  • fn := ObjBindMethod(fn, method, args*) --> fn[method](args*)
  • fn := ObjBind(fn, [method,] args*) --> IsObject(fn) ? fn[method](args*) : %fn%(args*) (i.e. ObjBind("FuncName", ...) = ObjBind(Func("FuncName"), "Call", ...)).
  • Multiple options (with a cost to code size).
Binding a method name can have its own uses, like binding to a method of a COM or File object or a method implemented via __Call. In those cases, there's no function to bind to. Usage could be ObjBindMethod(obj, "MethodName", ...) rather than bind(obj.MethodName, obj).

A difference between ObjBind/ObjBindMethod() and Func.Bind() is that the former would work on any kind of object, whereas the latter would only work on Func objects (and possibly BoundFunc objects, with a cost to code size).
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

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

22 Feb 2015, 19:57

Hrm, as usual I don't really get the implications of everything you are saying, but am I correct in assuming that you are talking about binding an object method to something other than the object?

ie myobj.dosomething() actually invokes someotherobj.blah()?

Also, are there any plans to provide alternatives to the Gui Event labels? (eg GuiClose:)
It would be nice to be able to trap these events without labels.
In the meantime, is there a windows message or something I can subscribe to that fires under the same conditions as GuiClose ?
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

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

22 Feb 2015, 20:32

am I correct in assuming that you are talking about binding an object method to something other than the object?
No. Which one of my syntax examples would lead you to think that? fn := ObjBindMethod(obj, method, args*), %fn%() would do obj[method](args*).

Binding a method to something other than its original object implies that the method itself exists/is an object. That's not the case for File.Read(), ComObj.Whatever() (in most cases), etc. If the method is a function, you can already bind it to some other object: bind(class.method, someOtherObj).
Also, are there any plans to provide alternatives to the Gui Event labels?
Other than using a function, which you can already do, and passing parameters to that function, no, I do not have any plans.
In the meantime, is there a windows message or something I can subscribe to that fires under the same conditions as GuiClose ?
WM_CLOSE? I think all of the GUI events are in response to messages.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

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

28 Feb 2015, 02:12

Update v1.1.19.03-37+gd7b054a

Added parameters to GUI event handlers, much like fincs proposed GUI API, but passing the GUI and/or control by HWND.

Code: Select all

GuiClose(gui)
GuiEscape(gui)
GuiSize(gui, eventInfo, width, height)
GuiContextMenu(gui, ctrl, eventInfo, isRightClick, x, y)
GuiDropFiles(gui, fileArray, ctrl, x, y)

CtrlEvent(ctrl, guiEvent, eventInfo, errorLevel)
If GuiClose is a function, the GUI is closed by default. This can be prevented by returning a non-zero integer.

For custom controls, the function's return value is used as the return value for WM_NOTIFY, instead of ErrorLevel.


Tentatively added ObjBindMethod(obj, method, args*) and Func.Bind(args*). Calling the returned object calls the function or method, passing the contents of args followed by any other parameters which were passed. For example:

Code: Select all

f := ObjBindMethod(X, "Y", 2)   ; f(a*) -> X.Y(2, a*)
%f%(3)  ; 123
f := X.Y.Bind(X, 2)             ; f(a*) -> (X.Y).Call(X, 2, a*)
%f%(3)  ; 123
f := Func("Fn").Bind(1)         ; f(a*) -> Fn(1, a*)
%f%(2)    ; 12
f.Call(3) ; 13

class X {
    static Z := 1
    Y(a, b) {
        MsgBox % this.Z a b
    }
}
Fn(a:=0, b:=0) {
    MsgBox % a b
}
TODO:
  • OnExit() - accept exit reason as a parameter and possibly allow multiple handlers.
  • Maybe add parameters for Menu item handlers. Probably not for hotkeys, since it's hard to say which variables are worth passing, and hotkeys will always primarily be labels.
geek
Posts: 1052
Joined: 02 Oct 2013, 22:13
Location: GeekDude
Contact:

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

28 Feb 2015, 15:55

Func().Bind is by reference, and ObjBindMethod is by name. Very interesting

Code: Select all

;#! %A_AhkPath%\..\AutoHotkey111903_37_gd7b054a_w.exe

; Says "A: 2"
f := TestClass1.A.Bind(TestClass1, 2)
TestClass1.A := TestClass1.B
%f%(3)

; Says "B: 2"
f := ObjBindMethod(TestClass2, "A", 2)
TestClass2.A := TestClass2.B
%f%(3)

class TestClass1
{
	A(Param)
	{
		MsgBox, "A: " Param
	}
	B(Param)
	{
		MsgBox, "B: " Param
	}
}

class TestClass2
{
	A(Param)
	{
		MsgBox, "A: " Param
	}
	B(Param)
	{
		MsgBox, "B: " Param
	}
}
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

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

05 Mar 2015, 06:39

Update v1.1.19.03-43+g90af137

Reverted the OnExit command to only accept a label name.
Added two functions:

Code: Select all

OnExit(Function [, Mode])
OnClipboardChange(Function [, Mode])
  • Function is a function name (string) or object. The function can accept one parameter, which receives the value of either A_ExitReason or A_EventInfo.
  • Mode is 0 to unregister the function, 1 to register it to be called last, or -1 to be called first.
Legacy OnExit and OnClipboardChange subs are always called first. This can't be changed, due to requirements imposed by the need for backward-compatibility.

OnExit functions can return 1 to prevent exit. Calling ExitApp from a legacy OnExit sub will still allow OnExit functions to be called. Calling ExitApp from an OnExit function will immediately exit the script (so in general, don't do it). If an OnExit function is designed to sometimes prevent exit, it should pass -1 for the last parameter to improve the odds that it will be called before any functions which are expecting the script to actually exit.

OnClipboardChange functions are not called when first registering the function. (By contrast, the OnClipboardChange label is always called once when the script starts.)

I went to considerable lengths to minimize the impact that these new features have on code size. The result is that this build is smaller than the previous one. :lol:

A bin file for compiling Unicode 32-bit scripts is included in the download.

Return to “Announcements”

Who is online

Users browsing this forum: No registered users and 34 guests