For-loop

Repeats a series of functions once for each key-value pair in an object.

For Value1 , Value2 in Expression

Parameters

Value1
Value2

Type: Variable

The variables in which to store the values returned by the enumerator at the beginning of each iteration. The nature of these values is defined by the enumerator, which is determined by Expression. These variables cannot be dynamic.

When the loop breaks or completes, these variables are restored to their former values. If a loop variable is a ByRef parameter, the target variable is unaffected by the loop. Closures which reference the variable (if local) are also unaffected and will see only the value it had outside the loop.

Note: Even if defined inside the loop body, a nested function which refers to a loop variable cannot see or change the current iteration's value. Instead, pass the variable explicitly or bind its value to a parameter.

Up to 19 variables are supported, if supported by the enumerator.

Variables can be omitted. For example, for , value in myMap calls myMap's enumerator with only its second parameter, omitting its first parameter. If the enumerator is user-defined and the parameter is mandatory, an exception is thrown as usual. The parameter count passed to __Enum is 0 if there are no variables or commas; otherwise it is 1 plus the number of commas present.

Expression

Type: Object

An expression which results in an enumerable object, or a variable which contains an enumerable object.

Remarks

The parameter list can optionally be enclosed in parentheses. For example: for (val in myarray)

The process of enumeration is as follows:

Although not exactly equivalent to a for-loop, the following demonstrates this process:

_enum := Expression
try _enum := _enum.__Enum(2)
while %_enum%(Value1, Value2)
{
    ...
}

As in the code above, an exception is thrown if Expression or __Enum does not yield a object, or if the enumerator object cannot be called.

While enumerating properties, methods or array elements, it is generally unsafe to insert or remove items of that type. Doing so may cause some items to be skipped or enumerated multiple times. One workaround is to build a list of items to remove, then use a second loop to remove the items after the first loop completes.

A for-loop is usually followed by a block, which is a collection of statements that form the body of the loop. However, a loop with only a single statement does not require a block (an "if" and its "else" count as a single statement for this purpose). The One True Brace (OTB) style may optionally be used, which allows the open-brace to appear on the same line rather than underneath. For example: for x, y in z {.

As with all loops, Break, Continue and A_Index may be used.

COM Objects

Since Value1 and Value2 are passed directly to the enumerator, the values they are assigned depends on what type of object is being enumerated. For COM objects, Value1 contains the value returned by IEnumVARIANT::Next() and Value2 contains a number which represents its variant type. For example, when used with a Scripting.Dictionary object, each Value1 contains a key from the dictionary and Value2 is typically 8 for strings and 3 for integers. See ComObjType for a list of type codes.

When enumerating a SafeArray, Value1 contains the current element and Value2 contains its variant type.

Related

Enumerator object, OwnProps, OwnMethods, While-loop, Loop, Until, Break, Continue, Blocks

Examples

#1: List the properties owned by an object:

colours := {red: 0xFF0000, blue: 0x0000FF, green: 0x00FF00}
; The above expression could be used directly in place of "colours" below:
s := ""
for k, v in colours.OwnProps()
    s .= k "=" v "`n"
MsgBox s

#2: List all open Explorer and Internet Explorer windows, using the Shell object.

windows := ""
for window in ComObjCreate("Shell.Application").Windows
    windows .= window.LocationName " :: " window.LocationURL "`n"
MsgBox windows

#3: Define an enumerator as a fat arrow function. Returns numbers from the Fibonacci sequence, indefinitely or until stopped.

for n in FibF()
    if MsgBox("#" A_Index " = " n "`nContinue?",, "y/n") = "No"
        break

FibF() {
    a := 0, b := 1
    return (ByRef n) => (
        n := c := b, b += a, a := c,
        true
    )
}

#4: Define an enumerator as a class. Equivalent to the previous example.

for n in FibC.new()
    if MsgBox("#" A_Index " = " n "`nContinue?",, "y/n") = "No"
        break

class FibC {
    a := 0, b := 1
    Call(ByRef n) {
        n := c := this.b, this.b += this.a, this.a := c
        return true
    }
}