Note: AutoHotkey v2.0-alpha is undergoing a paradigm shift. This version of the documentation pertains to v2.0-a101.

An object in AutoHotkey is an abstract datatype which provides three basic functions:

Related topics:

IsObject can be used to determine if a value is an object:

Result := IsObject(expression)

See Object Types in the documentation side bar for a list of standard object types. These include three main types:

Table of Contents

Basic Usage

Simple Arrays

Create an array:

MyArray := [Item1, Item2, ..., ItemN]
MyArray := Array(Item1, Item2, ..., ItemN)

Retrieve an item:

Value := MyArray[Index]

Assign an item:

MyArray[Index] := Value

Insert one or more items at a given index using the InsertAt method:

MyArray.InsertAt(Index, Value, Value2, ...)

Append one or more items using the Push method:

MyArray.Push(Value, Value2, ...)

Remove an item using the RemoveAt method:

RemovedValue := MyArray.RemoveAt(Index)

Remove the last item using the Pop method:

RemovedValue := MyArray.Pop()

If the array is not empty, MinIndex and MaxIndex/Length return the lowest and highest index currently in use in the array. Since the lowest index is nearly always 1, MaxIndex usually returns the number of items. However, if there are no integer keys, MaxIndex returns an empty string whereas Length returns 0. Looping through an array's contents can be done either by index or with a For-loop. For example:

MyArray := ["one", "two", "three"]

; Iterate from 1 to the end of the array:
Loop MyArray.Length()
    MsgBox MyArray[A_Index]

; Enumerate the array's contents:
For index, value in MyArray
    MsgBox "Item " index " is '" value "'"

Note: A future alpha release will change [], Array() and variadic functions to create a dedicated array type with restricted capabilities. See Objects (forum topic) for details.

Associative Arrays

Note: The following details apply to v2.0-a101 and may not be applicable to future alpha releases. See Objects (forum topic) for details.

An associative array is an object which contains a collection of unique keys and a collection of values, where each key is associated with one value. Keys can be strings, integers or objects, while values can be of any type. An associative array can be created as follows:

MyArray := {KeyA: ValueA, KeyB: ValueB, ..., KeyZ: ValueZ}
MyArray := Object("KeyA", ValueA, "KeyB", ValueB, ..., "KeyZ", ValueZ)

Using the {key:value} notation, quote marks are optional for keys which consist only of word characters. Any expression can be used as a key, but to use a variable as a key, it must be enclosed in parentheses. For example, {(KeyVar): Value} and {GetKey(): Value} are both valid.

Retrieve an item:

Value := MyArray[Key]

Assign an item:

MyArray[Key] := Value

Remove an item using the Delete method:

RemovedValue := MyArray.Delete(Key)

Enumerating items:

MyArray := {ten: 10, twenty: 20, thirty: 30}
For key, value in MyArray
    MsgBox key ' = ' value

Associative arrays can be sparsely populated - that is, {1:"a",1000:"b"} contains only two key-value pairs, not 1000.


An object can have properties, methods and items (such as array elements). Items are accessed using [] as shown in the previous sections. Properties and methods are usually accessed by writing a dot followed by an identifier (just a name).

Note: Currently properties and methods are defined as associative array elements, and as such, the syntax can usually be used interchangeably. However, this will be changed in a future alpha release. It is important to use the syntax appropriate to the situation.


Retrieve or set a property literally named Property:

Value := Object.Property
Object.Property := Value

Retrieve or set a property where the name is determined by evaluating an expression or variable:

Value := Object.%Expression%
Object.%Expression% := Value

Call a method literally named Method:

ReturnValue := Object.Method(Parameters)

Call a method where the name is determined by evaluating an expression or variable:

ReturnValue := Object.%Expression%(Parameters)

Note: Object[Expression](Parameters) can also be used, but will cease to work in a future release.

Some properties of COM objects and user-defined objects can accept parameters:

Value := Object.Property[Parameters]
Object.Property[Parameters] := Value

Related: Object, File Object, Func Object, COM object

Freeing Objects

Scripts do not free objects explicitly. When the last reference to an object is released, the object is freed automatically. A reference stored in a variable is released automatically when that variable is assigned some other value. For example:

obj := {}  ; Creates an object.
obj := ""  ; Releases the last reference, and therefore frees the object.

Similarly, a reference stored in a field of another object is released when that field is assigned some other value or removed from the object. This also applies to arrays, which are actually objects.

arr := [{}]  ; Creates an array containing an object.
arr[1] := {}  ; Creates a second object, implicitly freeing the first object.
arr.RemoveAt(1)  ; Removes and frees the second object.

Because all references to an object must be released before the object can be freed, objects containing circular references aren't freed automatically. For instance, if x.child refers to y and y.parent refers to x, clearing x and y is not sufficient since the parent object still contains a reference to the child and vice versa. To resolve this situation, remove the circular reference.

x := {}, y := {}             ; Create two objects.
x.child := y, y.parent := x  ; Create a circular reference.

y.parent := ""               ; The circular reference must be removed before the objects can be freed.
x := "", y := ""             ; Without the above line, this would not free the objects.

For more advanced usage and details, see Reference Counting.


Objects as Values

Object references can themselves be used in expressions:

If an object is used in any context where an object is not expected, it is typically treated as an empty string. For example, MsgBox(myObject) shows an empty MsgBox. Do not rely on this behaviour as it may change. In some cases an exception may be thrown, such as for myObject + 1 or Round(myObject).


Compound assignments such as x.y += 1 and --arr[1] are supported.

Parameters can be omitted when getting or setting properties. For example, x.y[,2] or x[,2]. Scripts can utilize this by defining default values for parameters in properties and meta-functions.

The method name can also be completely omitted, as in x[](a). This can be utilized by defining a default value for the __Call meta-function's first parameter.

Note: The use of brackets to replace the method name with an expression will not be supported in future alpha releases. To call a function object x, use x.Call() or %x%().

If the property or method name is omitted when invoking a COM object, its "default member" is invoked.


Note: The following details apply to v2.0-a101 and may not be applicable to future alpha releases. See Objects (forum topic) for details.

Objects created with [], {} or the new operator allow the use of strings, integers and objects as keys, with the following caveats:

The key's value is preserved, but its type identity is not. That is, integers may be stored as strings or vice versa, so long as the value remains the same (including the formatting of numeric strings). Specifically:

Some strings generally should not be used as keys:

Extended Usage

Function References

If the variable func contains a function name, the function can be called with the expression %func%(). However, this requires the function name to be resolved each time, which is inefficient if the function is called more than once. To improve performance, the script can retrieve a reference to the function and store it for later use:

MyFuncRef := Func("MyFunc")

A function can be called by reference using the following syntax:

RetVal := %MyFuncRef%(Params)
RetVal := MyFuncRef.Call(Params)

For details about additional properties of function references, see Func Object.

Arrays of Arrays

Note: The following details apply to v2.0-a101. Future alpha releases may not have built-in support for multi-dimensional arrays. See Objects (forum topic) for details.

AutoHotkey supports "multi-dimensional" arrays by transparently storing arrays inside other arrays. For example, a table could be represented as an array of rows, where each row is itself an array of columns. In that case, the content of column y of row x can be set using either of the methods below:

table[x][y] := content  ; A
table[x, y] := content  ; B

If table[x] does not exist, A and B differ in two ways:

Multi-dimensional assignments such as table[a, b, c, d] := value are handled as follows:

This behaviour only applies to script-created objects, not more specialized types of objects such as COM objects or COM arrays.

Arrays of Functions

An array of functions is simply an array containing function names or references. For example:

MyArray := [Func("FirstFunc"), Func("SecondFunc")]

; Call each function, passing "foo" as a parameter:
Loop 2

; Call each function, implicitly passing the array itself as a parameter:
Loop 2

FirstFunc(param) {
    MsgBox A_ThisFunc ": " (IsObject(param) ? "object" : param)
SecondFunc(param) {
    MsgBox A_ThisFunc ": " (IsObject(param) ? "object" : param)

Custom Objects

Note: The following details apply to v2.0-a101 and may not be 100% applicable to future alpha releases. See Objects (forum topic) for details.

Objects created by the script do not need to have any predefined structure. Instead, each object can inherit properties and methods from its base object (otherwise known as a "prototype" or "class"). Properties and methods can also be added to (or removed from) an object at any time, and those changes will affect any and all derived objects. For more complex or specialized situations, a base object can override the standard behaviour of any objects derived from it by defining meta-functions.

Base objects are just ordinary objects, and are typically created one of two ways:

class baseObject {
    static foo := "bar"
; OR
baseObject := {foo: "bar"}

To create an object derived from another object, scripts can assign to the base property or use the new keyword:

obj1 := Object(), obj1.base := baseObject
obj2 := {base: baseObject}
obj3 := new baseObject
MsgBox obj1.foo " " obj2.foo " " obj3.foo

It is possible to reassign an object's base at any time, effectively replacing all of the properties and methods that the object inherits.


Prototype or base objects are constructed and manipulated the same as any other object. For example, an ordinary object with one property and one method might be constructed like this:

; Create an object.
thing := {}
; Store a value.
thing.foo := "bar"
; Create a method by storing a function reference.
thing.test := Func("thing_test")
; Call the method.

thing_test(this) {
    MsgBox this.foo

When thing.test() is called, thing is automatically inserted at the beginning of the parameter list. By convention, the function is named by combining the "type" of object and the method name.

An object is a prototype or base if another object derives from it:

other := {}
other.base := thing

In this case, other inherits foo and test from thing. This inheritance is dynamic, so if thing.foo is modified, the change will be reflected by other.foo. If the script assigns to other.foo, the value is stored in other and any further changes to thing.foo will have no effect on other.foo. When other.test() is called, its this parameter contains a reference to other instead of thing.


At its root, a "class" is a set or category of things having some property or attribute in common. Since a base or prototype object defines properties and behaviour for set of objects, it can also be called a class object. For convenience, base objects can be defined using the "class" keyword as shown below:

class ClassName extends BaseClassName
    InstanceVar := Expression
    static ClassVar := Expression

    class NestedClass


    Property[]  ; Brackets are optional
        get {
            return value of property
        set {
            Store or otherwise handle value
        get => Expression which calculates property value
        set => Expression which stores or otherwise handles value
    ShorterProperty[] => Expression which calculates property value

When the script is loaded, this constructs an object and stores it in the super-global variable ClassName. To reference this class inside a force-local function, a declaration such as global ClassName is required. If extends BaseClassName is present, BaseClassName must be the full name of another class. The full name of each class is stored in object.__Class.

Because the class is referenced via a variable, the class name cannot be used to both reference the class and create a separate variable (such as to hold an instance of the class) in the same context. For example, box := new Box would replace the class object in Box with an instance of itself. #Warn ClassOverwrite enables a warning to be shown at load time for each attempt to overwrite a class.

Within this documentation, the word "class" on its own usually means a class object constructed with the class keyword.

Class definitions can contain variable declarations, method definitions and nested class definitions.

Instance Variables

An instance variable is one that each instance of the class (that is, each object derived from the class) has its own copy of. They are declared like normal assignments, but the this. prefix is omitted (only directly within the class body):

InstanceVar := Expression

These declarations are evaluated each time a new instance of the class is created with the new keyword. The method name __Init is reserved for this purpose, and should not be used by the script. The __New() method is called after all such declarations have been evaluated, including those defined in base classes. Expression can access other instance variables and methods via this, but all other variable references are assumed to be global.

To access an instance variable (even within a method), always specify the target object; for example, this.InstanceVar.

Declarations like x.y := z are also supported, provided that x was previously declared in this class. For example, x := {}, x.y := 42 declares x and also initializes this.x.y.

Static/Class Variables

Static/class variables belong to the class itself, but can be inherited by derived objects (including sub-classes). They are declared like instance variables, but using the static keyword:

static ClassVar := Expression

Static declarations are evaluated only once, before the auto-execute section, in the order they appear in the script. Each declaration stores a value in the class object. Any variable references in Expression are assumed to be global.

To assign to a class variable, always specify the class object; for example, ClassName.ClassVar := Value. If an object x is derived from ClassName and x itself does not contain the key "ClassVar", x.ClassVar may also be used to dynamically retrieve the value of ClassName.ClassVar. However, x.ClassVar := y would store the value in x, not in ClassName.

Declarations like static x.y := z are also supported, provided that x was previously declared in this class. For example, static x := {}, x.y := 42 declares x and also initializes ClassName.x.y.

Nested Classes

Nested class definitions allow a class object to be stored inside another class object rather than a separate global variable. In the example above, class NestedClass constructs an object and stores it in ClassName.NestedClass. Sub-classes could inherit NestedClass or override it with their own nested class (in which case new this.NestedClass could be used to instantiate whichever class is appropriate).

class NestedClass


Method definitions look identical to function definitions. Each method has a hidden parameter named this, which typically contains a reference to an object derived from the class. However, it could contain a reference to the class itself or a derived class, depending on how the method was called. Methods are stored by reference in the class object.


Inside a method, the pseudo-keyword base can be used to access the super-class versions of methods or properties which are overridden in a derived class. For example, base.Method() in the class defined above would call the version of Method which is defined by BaseClassName. Meta-functions are not called; otherwise, base.Method() behaves like BaseClassName.Method.Call(this). That is,

base only has special meaning if followed by a dot . or brackets [], so code like obj := base, obj.Method() will not work. Scripts can disable the special behaviour of base by assigning it a non-empty value; however, this is not recommended.

Fat arrow syntax can be used to define a single-line method which returns an expression:

Method() => Expression


Property definitions allow a method to be executed whenever the script gets or sets a specific key.

Property[]  ; Brackets are optional
    get {
        return property value
    set {
        Store or otherwise handle value

Property is simply the name of the property, which will be used to invoke it. For example, obj.Property would call get while obj.Property := value would call set. Within get or set, this refers to the object being invoked. Within set, value contains the value being assigned.

Parameters can be passed by enclosing them in square brackets to the right of the property name, both when defining the property and when calling it. Aside from using square brackets, parameters of properties are defined the same way as parameters of methods - optional, ByRef and variadic parameters are supported.

The return value of set is ignored. For example, val := obj.Property := 42 always assigns val := 42 regardless of what the property does, unless it throws an exception or exits the thread.

Each class can define one or both halves of a property. If a class overrides a property, it can use base.Property to access the property defined by its base class. If get or set is not defined, it can be handled by a base class. If set is not defined and is not handled by a meta-function or base class, assigning a value stores it in the object, effectively disabling the property.

Attempting to call a property, as in obj.Property(), will have the same effect as if the property did not exist.

Internally, get and set are two separate methods, so cannot share variables (except by storing them in this).

Meta-functions provide a broader way of controlling access to properties and methods of an object, but are more complicated and error-prone.

Fat Arrow Properties

Fat arrow syntax can be used to define a property getter or setter which returns an expression:

    get => Expression which calculates property value
    set => Expression which stores or otherwise handles value

When defining only a getter, the braces and get can be omitted:

ShorterProperty[] => Expression which calculates property value

__Item Property

The __Item property is invoked when the indexing operator (array syntax) is used with the object. For example:

class Env {
    __Item[name] {
        get => EnvGet(name)
        set => EnvSet(name, value)

Env["PATH"] .= ";" A_ScriptDir  ; Only affects this script and child processes.
MsgBox Env["PATH"]

For objects of type Object, __Item is effectively a default property name (if such a property has been defined). In effect:

Note: When an explicit property name is combined with empty brackets, as in obj.prop[], it is handled as two separate operations: first retrieve obj.prop, then invoke the default property of the result. This is part of the language syntax, so is not dependent on the object.

For example:

obj := {}
obj[] := {}              ; Equivalent to obj.__Item := {}
obj["Count"] := "Data"  
obj["Delete"] := "Data" 
MsgBox obj.Count()       ; 1 (just obj.__Item)
MsgBox obj.Count = ""    ; 1 (true)
obj.Count := 0          
MsgBox obj.Count()       ; Fail (0 cannot be called)

Construction and Destruction

Whenever a derived object is created with the new keyword, the __New method defined by its base object is called. This method can accept parameters, initialize the object and override the result of the new operator by returning a value. When an object is destroyed, __Delete is called. For example:

m1 := new GMem(0, 20)
m2 := {base: GMem}.__New(0, 30)

class GMem
    __New(aFlags, aSize)
        this.ptr := DllCall("GlobalAlloc", "UInt", aFlags, "Ptr", aSize, "Ptr")
        if !this.ptr
            return ""
        MsgBox "New GMem of " aSize " bytes at address " this.ptr "."
        return this  ; This line can be omitted when using the 'new' operator.

        MsgBox "Delete GMem at address " this.ptr "."
        DllCall("GlobalFree", "Ptr", this.ptr)

__Delete is not called for any object which has the key "__Class". Class objects have this key by default.

If an exception or runtime error is thrown while __Delete is executing and is not handled within __Delete, it acts as though __Delete was called from a new thread. That is, an error dialog is displayed and __Delete returns, but the thread does not exit (unless it was already exiting).


Method syntax:
class ClassName {
    __Get([Key, Key2, ...])
    __Set([Key, Key2, ...], Value)
    __Call(Name [, Params...])

Function syntax:
MyGet(this [, Key, Key2, ...])
MySet(this [, Key, Key2, ...], Value)
MyCall(this, Name [, Params...])

ClassName := { __Get: Func("MyGet"), __Set: Func("MySet"), __Call: Func("MyCall") }

Meta-functions define what happens when a key is requested but not found within the target object. For example, if obj.key has not been assigned a value, it invokes the __Get meta-function. Similarly, obj.key := value invokes __Set and obj.key() invokes __Call. These meta-functions (or methods) would need to be defined in obj.base, obj.base.base or such.

When the script gets, sets or calls a key which does not exist within the target object, the base object is invoked as follows:

If a meta-function stores a matching key in the object but does not return, the behaviour is the same as if the key initially existed in the object. For an example using __Set, see Sub-classing Arrays of Arrays.

If the operation still hasn't been handled, check if this is a built-in method or property:

If the operation still hasn't been handled,

Known limitation:

Dynamic Properties

Property syntax can be used to define properties which compute a value each time they are evaluated, but each property must be known in advance and defined individually in the script. By contrast, __Get and __Set can be used to implement properties which aren't known by the script.

For example, a "proxy" object could be created which sends requests for properties over the network (or through some other channel). A remote server would send back a response containing the value of the property, and the proxy would return the value to its caller. Even if the name of each property was known in advance, it would not be logical to define each property individually in the proxy class since every property does the same thing (send a network request). Meta-functions receive the property name as a parameter, so are a good solution for this problem.

Another use of __Get and __Set is to implement a set of related properties which share code. In the example below they are used to implement a "Color" object with R, G, B and RGB properties, where only the RGB value is actually stored:

red  := new Color(0xff0000), red.R -= 5
cyan := new Color(0), cyan.G := 255, cyan.B := 255

MsgBox "red: " red.R "," red.G "," red.B " = " red.RGB
MsgBox "cyan: " cyan.R "," cyan.G "," cyan.B " = " cyan.RGB

class Color
        this.RGB := aRGB

    static Shift := {R:16, G:8, B:0}

        ; NOTE: Using this.Shift here would cause an infinite loop!
        shift := Color.Shift[aName]  ; Get the number of bits to shift.
        if (shift != "")  ; Is it a known property?
            return (this.RGB >> shift) & 0xff
        ; NOTE: Using 'return' here would break this.RGB.

    __Set(aName, aValue)
        if ((shift := Color.Shift[aName]) != "")
            aValue &= 255  ; Truncate it to the proper range.

            ; Calculate and store the new RGB value.
            this.RGB := (aValue << shift) | (this.RGB & ~(0xff << shift))

            ; 'Return' must be used to indicate a new key-value pair should not be created.
            return aValue
        ; NOTE: Using 'return' here would break this.stored_RGB and this.RGB.

    ; Meta-functions can be mixed with properties:
    RGB {
        get {
            ; Return it in hex format:
            return format("0x{:06x}", this.stored_RGB)
        set {
            return this.stored_RGB := value

However, in this case Property syntax could have been used instead, where code is shared by simply having each property call a central method. It is better to avoid using meta-functions where possible due to the high risk of misuse (see the notes in red above).

Objects as Functions

For an outline of how to create objects which can act as functions, see Function Objects.

A function object can also act as a meta-function, such as to define dynamic properties similar to those in the previous section. Although it is recommended to use property syntax instead, the example below shows the potential of meta-functions for implementing new concepts or behaviour, or changing the structure of the script.

blue := new Color(0x0000ff)
MsgBox blue.R "," blue.G "," blue.B

class Properties
    Call(aTarget, aName, aParams*)
        ; If this Properties object contains a definition for this half-property, call it.
        if ObjHasKey(this, aName)
            return this[aName].Call(aTarget, aParams*)

class Color
        this.RGB := aRGB

    class __Get extends Properties
        R() {
            return (this.RGB >> 16) & 255
        G() {
            return (this.RGB >> 8) & 255
        B() {
            return this.RGB & 255


Sub-classing Arrays of Arrays

When a multi-parameter assignment such as table[x, y] := content implicitly causes a new object to be created, the new object ordinarily has no base and therefore no custom methods or special behaviour. __Set may be used to initialize these objects, as demonstrated below.

x := {base: {addr: Func("x_Addr"), __Set: Func("x_Setter")}}

; Assign value, implicitly calling x_Setter to create sub-objects.
x[1,2,3] := "..."

; Retrieve value and call example method.
MsgBox x[1,2,3] "`n" x.addr() "`n" x[1].addr() "`n" x[1,2].addr()

x_Setter(x, p1, p2, p3) {
    x[p1] := new x.base

x_Addr(x) {
    return &x

Since x_Setter has four mandatory parameters, it will only be called when there are two or more key parameters. When the assignment above occurs, the following takes place:

Default Base Object

When a non-object value is used with object syntax, the default base object is invoked. This can be used for debugging or to globally define object-like behaviour for strings, numbers and/or variables. The default base may be accessed by using .base with any non-object value; for instance, "".base. Although the default base cannot be set as in "".base := Object(), the default base may itself have a base as in "".base.base := Object().

Automatic Var Init

When an empty variable is used as the target of a set operation, it is passed directly to the __Set meta-function, giving it opportunity to insert a new object into the variable. For brevity, this example does not support multiple parameters; it could, by using a variadic function.

"".base.__Set := Func("Default_Set_AutomaticVarInit")

empty_var.foo := "bar"
MsgBox empty_var.foo

Default_Set_AutomaticVarInit(ByRef var, key, value)
    if (var = "")
        var := Object(key, value)
    return var


Object "syntax sugar" can be applied to strings and numbers.

"".base.__Get := Func("Default_Get_PseudoProperty")
"".base.is    := Func("Default_is")

MsgBox A_AhkPath.length " == " StrLen(A_AhkPath)
MsgBox A_AhkPath.length.is("int")

Default_Get_PseudoProperty(nonobj, key)
    if (key = "length")
        return StrLen(nonobj)

Default_is(nonobj, type)
    static alias := {int: "integer"}
    return nonobj is (alias[type] or type)

Note that built-in functions may also be used, but in this case the parentheses cannot be omitted:

"".base.length := Func("StrLen")
MsgBox A_AhkPath.length() " == " StrLen(A_AhkPath)


By default, invoking a non-object value causes an exception to be thrown. The following example changes the behaviour so that a warning is shown and the script continues:

"".base.__Get := "".base.__Set := "".base.__Call := Func("Default__Warn")

empty_var.foo := "bar"
x := (1 + 1).is("integer")

Default__Warn(nonobj, p1:="", p2:="", p3:="", p4:="")
    MsgBox "A non-object value was improperly invoked.`n`nSpecifically: " nonobj
    return "" ; Override the default behaviour by explicitly returning.



AutoHotkey uses a basic reference-counting mechanism to automatically free the resources used by an object when it is no longer referenced by the script. Script authors should not invoke this mechanism explicitly, except when dealing directly with unmanaged pointers to objects.

Temporary references returned by functions, methods or operators within an expression are released after evaluation of that expression has completed or been aborted. This allows temporary objects to be used for resource management. For example:

MsgBox DllCall("GlobalSize", "ptr", (new GMem(0, 20)).ptr, "ptr")  ; 20

To run code when the last reference to an object is being released, implement the __Delete meta-function.

Known Limitations:

Although memory used by the object is reclaimed by the operating system when the program exits, __Delete will not be called unless all references to the object are freed. This can be important if it frees other resources which are not automatically reclaimed by the operating system, such as temporary files.

Pointers to Objects

In some rare cases it may be necessary to pass an object to external code via DllCall or store it in a binary data structure for later retrieval. An object's address can be retrieved via address := &object; however, this effectively makes two references to the object, but the program only knows about the one in object. If the last known reference to the object was released, the object would be deleted. Therefore, the script must inform the object that it has gained a reference. This can be done as follows:

ObjAddRef(address := &object)

The script must also inform the object when it is finished with that reference:


Generally each new copy of an object's address should be treated as another reference to the object, so the script should call ObjAddRef when it gains a copy and ObjRelease immediately before losing one. For example, whenever an address is copied via something like x := address, ObjAddRef should be called. Similarly, when the script is finished with x (or is about to overwrite x's value), it should call ObjRelease.

To convert an address to a proper reference, use the Object function:

MyObject := Object(address)

Note that the Object function can be used even on objects which it did not create, such as COM objects and File objects.