Thoughts for v2.0



As commands and functions are still internally distinct in the current v2 alpha, defining a function with the same name as a command overrides the command only for the function() style of calling; i.e. the command style still calls the original command. This should be changed.

Commands with sub-commands

The remaining commands which have sub-commands are: DriveGet, Drive, Control, ControlGet, GuiControl and GuiControlGet.


MsgBox params could use reordering. As a function, its return value should indicate which button the user clicked (as in A_MsgBoxResult).

Rename MouseClickDrag, perhaps to MouseDrag?

MouseClick has been superseded by Click. Should MouseClick be removed? Should Click be renamed to MouseClick, for consistency with MouseMove?

TrayTip: TrayTip Title (omitting Text) is confusing, particularly because of ToolTip Text: the title is ignored and any existing TrayTip is removed. There are a few possible solutions:

TrayTip's Seconds parameter has no effect on Vista and later, so maybe it should come after Options. Alternatively, it might be more usable (and less confusing when using v1 code) to accept a string of named options such as Info Warning Error Mute Large T3 (where the first three are mutually-exclusive). MsgBox and InputBox also have Title, Text and Options parameters so it might be good to have all three commands use the same order.

Error Handling

Note that some changes have already been made which won't be covered here.

Errors in math operations

In v1, math operators silently produce an empty string in the following cases:

Additionally, there have been debates about whether empty strings should be treated as 0. Treating empty strings as 0 seems to be the preferred option. The disadvantage to error-detection ability can be offset by introducing a new mode for the #Warn directive.

Math with non-numeric values and divide by zero should not produce a number. If empty strings are treated as zero, these errors must not produce an empty string. The alternatives are to throw an exception or to produce some other non-numeric value, such as the string "NaN" (reminiscent of JavaScript's special NaN value).

The current v2 behaviour has not yet been finalized.

Errors in math functions

Math functions such as Round() could have the same behaviour as math operators. Currently in v1 and prior to v2.0-a064 they default to zero when provided with invalid input, and report errors (if detected) only by returning an empty string.

Error cases which are detected:

Other functions don't detect invalid input; non-numeric values default to 0.


In v1, COM errors are given special treatment for little reason.



Meta-functions are commonly misunderstood, and should probably be simplified. Random ideas:


Object.GetAddress(key) should return the address of an empty string if that's what Object[key] contains, since some scripts may want to assign a string and then pass its address to DllCall or similar. Currently such scripts need to call SetCapacity after assigning an empty string.

Objects now support binary zero in string values, by storing the length of the string. However, now only data up to the string length is preserved when cloning the object (consistent with retrieving the value from the object as a string, such as to assign to another object). There should be some way to set the length of data, such has Object.SetLength(Key, Length). For clarity (and to avoid confusion with Object.Length), it might be better to have SetStrLen and SetByteLen. Also consider that similar functions might be needed for variables, to better support binary data.

Some users have requested Object.Count(). Usage could be Object.Count([MinKey, MaxKey]), returning the number of key-value pairs in that range (or in total if there are no parameters).

new MyClass[a,b,c] could be reserved as a more convenient way to initialize a specialised array/collection type (new MyClass{a:b} is already "reserved" by way of being treated as a syntax error). Currently MyClass[a,b,c] could be a class to instantiate, but it's unlikely to have been used much (if at all), and is inconsistent with the v1 policy of requiring a class name after the new operator. v1 treats new x[y](z) as new c1 where c1 = x[y](z), while v2-a076 treats it as new c2(z) where c2 = x[y].

SafeArray objects should perhaps gain a .Length() method for consistency with plain Objects.

ComObjConnect() events currently dereference ByRef VARIANTs automatically (since some languages pass this whenever a variable is passed from script), which prevents the function from being able to pass back a value in some cases. We could either a) pass a ByRef wrapper allowing assignments such as param[] := value or b) automatically pass a variable and update the VARIANT after the function is called. Other (i.e. non-VARIANT) ByRef combinations are not dereferenced, and param[] := value is already supported in v1.1.17+.


Allow base to be defined as a nested class (and actually set the base class), so that meta-functions and properties can be easily defined for the class itself, within the class.

Make base a reserved word in class methods. Currently it is given special meaning when followed by . or [, except when the variable base has been assigned a value. Reserving the word simplifies the language and may improve performance.

If base is reserved everywhere, it could be used for calling an overridden built-in function (such as base.WinMove(x, y) in a redefinition of WinMove).


These were tentative ideas. Encouraging "OO" syntax is not my intended direction for AutoHotkey (especially with numbers and strings), so these probably won't be implemented.

Allow the script to define classes String and Number with methods and properties for all strings or numbers. Currently this is done by setting properties of the "".base object, but this affects all types of values except objects.

Allow the script to define global methods and properties for all objects, perhaps via an Object base class. By default this class would contain built-in methods such as Insert, allowing them to be redefined the same way that user-defined methods are. For example, a user-defined Insert method might call base.Insert(value) instead of ObjInsert(this, value).

Both of the above may require some way to append to an existing class, which may also be useful for user-defined classes. This could be allowed simply by repeating class ClassName {} or with an additional keyword for clarity, such as class ClassName extended {}. The keyword might imply that the initial and extended definitions must be placed in that specific order (rather than having two similar definitions which can be placed in any order), which mightn't be ideal. Another option is to allow ClassName.MethodName() declarations outside classes, allowing existing classes to be extended (and also allowing more flexibility over the organization of code).