In short:
- Variables and functions are combined.
- Properties and methods are combined (as in v1 or prior to v2.0-a104).
- Variable scope is resolved differently (in particular, global variables).
- ByRef works differently.
For a little more context, see
Preview of changes: scope, function and variable references. For more details, see the
documentation.
Names
Function and variable names are now placed in a shared namespace.
- Each function definition creates a constant (read-only variable) within the current scope; therefore, scripts cannot assign to a variable with that name in the same scope.
- Use MyFunc in place of Func("MyFunc").
- Use MyFunc in place of "MyFunc" when passing the function to any built-in function such as SetTimer or Hotkey. Passing a name (string) is no longer supported.
- Use myVar() in place of %myVar%() when calling a function by value.
- To call a function when all you have is a function name (string), first use a double-deref to resolve the name to a variable and retrieve its value (the function object). %myVar%() now actually performs a double-deref and then calls the result, equivalent to f := %myVar%, f(). Avoid handling functions by name (string) where possible; use references instead.
Further details:
- Object(), Array() and Map() now call the corresponding classes; they are no longer functions. Array and Map have the same usage as before, but Object no longer accepts parameters.
- Func and IsFunc have been removed.
- As built-in functions such as SetTimer no longer accept function names, passing A_ThisFunc will not work. However, %A_ThisFunc% should resolve to the Func or Closure, which would work.
Scope
Super-global variables have been removed (excluding built-in variables, which aren't quite the same as they cannot be redeclared or shadowed). In theory, removing them as an option makes the language and documentation a little simpler, and encourages code that is more robust, at the expense of a little lost convenience (possibly gained by not having to debug certain kinds of issues).
Within an assume-local function, if a given name is not used in a declaration or as the target of a non-dynamic assignment or the reference (&) operator, it may resolve to an existing global variable.
In other words:
- Functions can now read global variables without declaring them.
- Functions which have no global declarations cannot directly modify global variables (eliminating one source of unintended side-effects).
- Adding a new class to the script is much less likely to affect the behaviour of any existing function, as classes are not super-global.
- The global keyword is currently redundant when used in global scope, but can be used for clarity. Variables declared this way are now much less likely to conflict with local variables (such as when combining or #including scripts), as they are not super-global. On the other hand, some convenience is lost.
- Declarations are generally not needed as much.
Force-local mode has been removed. It was mostly added to protect a function against unintended references to super-global variables, and would have been even more inconvenient to use than before with the need to declare every global function being called by the function.
Fat arrow functions in global scope are no longer assume-global. Due to the new rules, they can read global variables and create local variables, but not assign global variables.
Expressions in class variable initializers can now create variables local to the implicit __Init method, and can read global variables but cannot assign them.
Expressions
Function calls now permit virtually any sub-expression for specifying which function to call, provided that there is no space or tab before the open-parenthesis of the parameter list. For example,
MyFunc() would call the value
MyFunc regardless of whether that is the function's actual name or a variable containing a function object, and
(a?b:c)() would call either
b or
c depending on
a. Note that
x.y() is still a method call roughly equivalent to
(x.y)(x), but
a[n]() is now equivalent to
(a[n])().
&var is now the "reference" operator, which is used with all ByRef and OutputVar parameters to improve clarity and flexibility (and make other language changes possible). See
VarRef in the documentation index for more details.
super() is now equivalent to
super.call().
Reading an unset variable now raises an error.
#Warn UseUnsetLocal and
#Warn UseUnsetGlobal have been removed.
Double-derefs such as
%var% are no longer capable of creating new variables. This avoids some inconsistencies, in particular relating to the new scope rules. They were already becoming less useful due to a fundamental incompatibility with
#Warn VarUnset, which is a very useful tool for error detection. Aside from that, new users sometimes find pseudo-arrays as the answer to a problem, when they would be better served by learning to use a basic array. This removes the inferior option.
Functions
No auto-include: Scripts are no longer automatically included from the function library (Lib) folders when a function call is present without a definition, due to increased complexity and potential for accidents (now that the
MyFunc in
MyFunc() can be any variable).
#Include <LibName> works as before. It may be superseded by module support in a future release.
A
/validate command-line switch was added to serve the secondary purpose of the
/iLib tempfile switch; i.e. load the script, display any warnings and error, then exit without running the script.
/iLib currently does the same thing as
/validate, since there are no auto-includes to write to
tempfile (Ahk2Exe and other scripts might rely on it).
A closure can now refer to itself or other closures by name (of the read-only variable implicitly created by the function definition) without creating a circular reference. Nested functions can now be used in the same outer function as a closure without necessarily becoming a closure (i.e. because they don't capture any variables or closures of the outer function).
ByRef
ByRef parameters are now declared using
¶m instead of
ByRef param, with some differences in usage.
ByRef parameters no longer implicitly take a reference to the caller's variable. Instead, the caller must explicitly pass a reference with the reference operator (
&var). This allows more flexibility, such as storing references elsewhere, accepting them with a variadic function and passing them on with a variadic call.
When a parameter is marked ByRef, any attempt to explicitly pass a non-VarRef value causes an error to be thrown. Otherwise, the function can check for a reference with
param is VarRef and explicitly dereference it with
%param%. IsByRef has been removed.
DllCall: The output value (if any) of numeric parameters with the * or P suffix is ignored if the script passes a plain variable containing a number. To receive the output value, pass a
VarRef such as
&myVar or an object with a
Ptr property.
Classes/Objects
Methods and properties are merged once again, so the following were removed: ObjOwnMethods, DefineMethod, DeleteMethod, HasOwnMethod, OwnMethods.
Methods of classes (both built-in and user-defined) are defined as simple value properties.
Static New is renamed to Call, so use
MyClass() to instantiate classes. However, an implication of the way methods work is that
MyClass.NestedClass() will pass
MyClass as
this, which ends up being the first parameter of __New.
(MyClass.NestedClass)() and
MyClass.NestedClass.Call() will work as
MyClass.NestedClass.New() did before.
Property descriptors accepted by DefineProp and returned by GetOwnPropDesc have an additional property
Call, which specifies a function object to be called when the property is called. If not defined for a call such as
x.y(), the
y property's getter is called to retrieve a function object, which is then called.
The RegExMatch object's type (class) name is now RegExMatchInfo, since
RegExMatch is a function and does not match the usage of a constructor.
Unrelated Bugfix
Fixed hotstrings with potential OTB to interpret R/T correctly.
- Fixed ::RT::{ not interpreted as OTB due to R or T in hotstring.
- Fixed :R0 T:x::{ interpreted as OTB due to R0 eclipsing T.
- Cleaned up and optimized.