Show pageOld revisionsBacklinksFold/unfold allBack to top This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. ====== v2 Objects ====== ===== What is an Object? ===== In its simplest form, an object stores a collection of values that can be accessed by a key, like a name or a list index. You can think of an object like a box that groups a bunch of variables together, where the variable names are the keys and the variable contents are the values. A collection of keys that map to values is called a [[https://en.wikipedia.org/wiki/Key%E2%80%93value_database|key-value store]]. Commonly, key-value stores are described as being like //dictionaries// or //phone books//. In the case of a dictionary, the word you are looking up is the key and the definition of the word is the value. For a phone book, the name you are looking up is the key and the phone number is the value. Most AutoHotkey v2 objects have //two// key-value stores, which is an upgrade from v1 where all objects had a single store. These two stores are the //property store// and the //item store//. The //property store// holds values that assist with you writing your code, called properties. For example, the ''Length'' property will give you a value that shows how many items are in a list. The //property store// uses keys that you will hard-code in your script, like how you might hard code variable names in expressions. The property store is accessed by //dot notation//, for example: ''object.Key'' where ''Key'' is the literal text for the key name. The code ''MsgBox object.Length'' will check the property store of ''object'' for the ''Length'' property. The //item store// holds keys and values, and is designed to hold data where the keys could be supplied by a variable. For example, if you are accessing items from the item store in a loop you might use the loop index variable ''A_Index'' for the key. The //item store// is accessed by //bracket notation//, for example: ''object["Key"]'' where ''"Key"'' is quoted text, a variable, or some other expression. AutoHotkey v2 has many built-in object types. For now we'll focus on these three: //Basic objects//, //Map objects//, and //Array objects//. ===== Built-In Object Types ===== ==== Basic Objects ==== Basic objects are the foundation for all other types of objects in AutoHotkey. They have very few properties defined, and do not define an item store. Basic objects are created using either curly braces (''{}''), or by creating a new instance of the Object class (''Object()''). Basic objects should be used when you need to store a collection of keys and values, where the keys do not change and will be hard coded into the script. <runner ahk2> ; Define a new object with three properties in the property store box := { width: 57, length: 70, height: 12 } MsgBox "The box is " box.width " units wide" box.width += 1 ; Increase the box object's width by 1 MsgBox "The box is now " box.width " units wide"</runner> ==== Arrays ==== Arrays are based on basic objects, and are used to store a list of items, numbered (//indexed//) starting at ''1''. Arrays are created using either square brackets (''[]''), or by creating a new instance of the Array class (''Array()''). Between the brackets, or the parentheses of the call to ''Array()'', you can put a comma delimited list of items to save to the array's //item store//. <runner ahk2> fruits := [ "apple", "banana", "orange" ] ; Access the array's item store using bracket notation, and get the first item MsgBox "The first fruit is " fruits[1] </runner> Arrays have a variety of built-in properties / methods that can be used to interact with the list of items. <runner ahk2> myList := [] ; Use dot notation to access property Length from the property store. MsgBox "My list has " myList.Length " items" ; Use dot notation to access method Push from the property store. ; Push adds a new item to the Array myList.Push("brick") MsgBox "My list has " myList.Length " items now! Item 1 is " myList[1] </runner> Unlike in AutoHotkey v1, arrays are not //sparse//. In v1, you could specify any new index for an array and assign a value into it. However, in v2 you cannot specify new indexes and all indexes are //contiguous// to existing indexes. So while in v1 you could take an array with three items and assign a new item at index 54, in v2 you can only assign indexes between ''1'' and ''array.Length''. If you want to extend the array, you **must** use the //Push// method, or pre-extend the length like ''array.Length := 54''. ==== Maps ==== Maps are based on basic objects, and are used to store unordered items where the keys can be text, numbers, other objects. Maps are created by creating a new instance of the Map class (''Map()''). When creating an instance of the Map class, you can provide any amount of keys and values, in the form ''Map(Key1, Value1, Key2, Value2, Key3, Value3)''. <runner ahk2> fruits := Map( "apple", "A sweet, crisp fruit in various colors, commonly eaten fresh.", "banana", "A long, curved fruit with soft flesh and a thick yellow peel.", "orange", "A citrus fruit with a tough orange rind and juicy, tangy flesh." ) ; Access the array's item store using bracket notation, to get the definition of Apple MsgBox 'The definition of "apple" is: ' fruits["apple"] </runner> Maps have a variety of built-in properties / methods that can be used to interact with the set of items. <runner ahk2> myList := Map() ; Use dot notation to access property Length from the property store. MsgBox "My map has " myList.Count " items" ; Use dot notation to access method Set from the property store. ; Set adds a new item to the Map or updates an existing item myList.Set("stone", "A naturally occurring solid piece of mineral matter used in construction.") ; Use bracket notation to do the same thing as the Set method. myList["brick"] := "A small, rectangular block of clay, used in building construction." MsgBox 'My list has ' myList.Count ' items now! Item "stone" is: ' myList["stone"] </runner> ===== Maps versus Objects ===== In AutoHotkey v1, there was no separation between Maps and basic Object types. In AutoHotkey v2, it is possible to misuse a basic object in many of the situations where maps will be more appropriate. Let's talk about that! AutoHotkey's object model is based largely on JavaScript, and in v1 object definition was so similar that you could in some cases paste JavaScript Object Notation (JSON) directly into your script. In v2, if you tried this you would run into two problems. First, object keys for the property store are no longer accepted if they are in quotes. Instead, they must follow similar rules to putting a variable name. Second, if you load data with dynamic keys into your objects' property stores, you run the risk of //shadowing// instance methods. In JavaScript, shadowing instance methods is almost never a concern because the language development group has bent over backwards to avoid putting reasonable instance methods onto their objects. The set of instance methods on basic objects in JavaScript are as follows: * Object.prototype.**hasOwnProperty**() * Object.prototype.**isPrototypeOf**() * Object.prototype.**propertyIsEnumerable**() * Object.prototype.**toLocaleString**() * Object.prototype.**toString**() * Object.prototype.**valueOf**() Notably, this set of methods contain almost nothing critical to the usage of most objects. If we loaded some data with dynamic names and ''toString'' was overwritten, barely anything of value would be lost. The basic object's implementation of ''toString'' mostly just returns ''"[object Object]"'' which was already unhelpful and mostly unused. Compare this to the set of methods available for basic objects in AutoHotkey: * **Clone**: Returns a shallow copy of an object. * **DefineProp**: Defines or modifies an own property. * **DeleteProp**: Removes an own property from an object. * **GetOwnPropDesc**: Returns a descriptor for a given own property, compatible with DefineProp. * **HasOwnProp**: Returns 1 (true) if an object owns a property by the specified name. * **OwnProps**: Enumerates an object's own properties. Plus the methods available on all values: * **GetMethod**: Retrieves the implementation function of a method. * **HasBase**: Returns true if the specified base object is in the value's chain of base objects. * **HasMethod**: Returns true if the value has a method by this name. * **HasProp**: Returns true if the value has a property by this name. You can see, these methods are immediately much more useful than the JavaScript ones. Why is that? JavaScript painted itself into a box. Because they enabled developers to treat basic objects like maps from the start, they can no longer add new instance methods to basic objects without risking issues with web scripts that already exist out there in the world. Instead, they implement all new object functionality as static methods instead of instance methods. AutoHotkey v2 doesn't have to worry about breaking existing scripts, because very few existing scripts for AHKv2 existed at its release, and going forward it encourages developers to avoid treating basic objects like maps. Instead of promising AHK won't add new important object instance methods, AHK promises the opposite; it can add new important object instance methods at any time and you should be ready for them. See here, a comparison of AHK's instance methods vs JavaScript's static methods (that operate more like really syntactically unwieldy instance methods). ^ AutoHotkey ^ JavaScript ^ | ''myObj.DefineProp(name, ...)'' | ''Object.defineProperty(myObj, name, ...)'' | | ''myObj.OwnProps()'' | ''Object.entries(myObj)'' | | ''myObj.GetOwnPropDesc(name)'' | ''Object.getOwnPropertyDescriptor(myObj, name)'' | So in JavaScript, you can have an object where its property ''entries'' gets populated at run-time by some data loaded from the web with zero repercussions. But the trade-off is that you will never be able to use ''entries'' as an instance method. Whereas in AutoHotkey v2, you can use ''OwnProps'' as an instance method but you will never be able to safely load property names from the web without the potential that your object could break outright later in the script because ''OwnProps'', ''Clone'', or some other critical method now or in the future was shadowed. It could be shadowed unintentionally, because words like Clone are somewhat common, or it could be shadowed intentionally by someone with malicious intent to break your script. Let's give an example: > Anecdote from [[user:geek]] > > Before AHKv2 was even a twinkle of light in the distance, I used various AHK socket libraries to create a chat bot for the AutoHotkey IRC help chat. This chat bot, among other things, kept a scoreboard to track how helpful people were being in the chat. Whenever someone would type ''!kudos userName'', that user would get 1 point added to their score. It was a very simple feature, with very simple code (AHKv1): > > <code autohotkey> scores := FileOpen("scores.json", "r").Read() scores := JSON.Load(scores) scores[targetUser]++ scores := JSON.Dump(scores) FileOpen("scores.json", "w").Write(scores) </code> > What would you say the issue with this code is? It's easy not to pick up on it right away, or at all. The issue here is //what happens when someone with the username ''_NewEnum'' gets a kudos point?// > > Well, I'll tell you what happens. On line 1 it loads the score board, on line 2 it parses the score board as JSON, on line 3 it shadows the built-in ''_NewEnum'' name, on line 4 the JSON library fails to list the object properties (returning '{}'), and on line 5 it deletes the scoreboard leaving an entirely empty scoreboard in its place. > > I could blocklist names that I think would cause potential issues, like ''_NewEnum'' or ''Clone'' (which are both perfectly valid names on IRC in general), but that's not a reliable approach because it both limits what I can do, and it's a moving target as future methods continue to be added to basic objects. > > Although this example is relatively low stakes, it demonstrates the class of bug very succinctly. If you use dynamic names for object properties, you open yourself up to potential future attacks on the very reliability of your code. Because it's potentially unsafe to use property names generated by some expression, AutoHotkey v2 makes the syntax for that rather unwieldy. Instead of ''{"property": "value"}'' which implies the property can and should be generated at runtime, AHKv2 has you write ''{property: "value"}'' which more correctly conveys the semantic difference that property store names really should be hard-coded into the script instead of loaded dynamically from a source that could contain breaking keys. If you did want to specify a property name from a variable source, you'd have to write ''{%someVar%: "value"}'' which is immediately a red flag because the usage of percentage signs in this context goes against all the changes and removal of legacy syntax from the v1 to v2 jump. Instead of misusing basic objects to load dynamic property names, AutoHotkey v2 provides the Map object with its item store which can store items of //any// name without worrying about shadowing important built-in names. It's only a few extra characters up front to write, but it entirely avoids the aforementioned preventable issues, and you can also avoid having to request the OwnProps iterator every time. See below, the two options really shake about the same in terms of how much code there is to write: <runner ahk2> myObject := {a: "alpha", b: "bravo", c: "charlie"} for key, value in myObject.OwnProps() { ; This loop only works because OwnProps is not defined as user data on myObject MsgBox "Plain object - " key ": " value } ; versus myObject := Map("a", "alpha", "b", "bravo", "c", "charlie") for key, value in myObject { ; This loop works even if OwnProps is defined as user data on myObject MsgBox "Map object - " key ": " value } </runner> So the rule of thumb is: If your all of your keys are known at the time you're writing the script, and you can hard-code them into the script, you can use a basic object with the property store. If your keys cannot be known at the time you're writing the script (like because they're loaded from a resource external to the script) then you should use a ''Map'' to be sure you never shadow the important methods that you might need later in the script. ==== Breaking the Rules ==== If you really must break the rule of thumb and load dynamic names into a basic object's property store, keep these two things in mind: First, if you are //sure// the data source you're loading from can never contain names that would conflict with the built-in names you need, you can actually do this safely. Second, if you do not care about polymorphism and the other advantages of a rigorous object implementation, you can use AutoHotkey like JavaScript and avoid using //any// of the built in instance methods. That is, you could write all your code with the equivalent functions instead of method calls. Since you would no longer need any of the built-in methods, you don't have to worry about shadowing them accidentally. <runner ahk2> myObject := {OwnProps: "Own Properties"} for key, value in ObjOwnProps(myObject) { ; This loop works even though OwnProps was overridden MsgBox "ObjOwnProps - " key ": " value } </runner> This reduces the flexibility of the script in the future. For example, imagine that a new object base implementation was offered by a library. Maybe the library uses some kind of hash mapping to make the property store more performant. Maybe the library offers the object as an RPC proxy for a remote environment (this is sometimes done for things like accessing certain JavaScript values from the WebView2 library). If you forcibly use the ''ObjOwnProps'' or other default object method implementations, you could severely limit compatibility with the new object type from that library. <runner ahk2> ; Some function you write using ObjOwnProps ObjectProcessor1(someObject) { for key, value in ObjOwnProps(someObject) MsgBox "ObjOwnProps - " key ": " value } ; Some function you write using object.OwnProps ObjectProcessor2(someObject) { try for key, value in someObject.OwnProps() MsgBox ".OwnProps() - " key ": " value } normalObject := {OwnProps: "", a: "Alpha"} customObject := CoolerObject() customObject.a := "Alpha" MsgBox "Fine:" ObjectProcessor1(normalObject) MsgBox "Wonky:" ObjectProcessor1(customObject) MsgBox "Broken:" ObjectProcessor2(normalObject) MsgBox "Fine:" ObjectProcessor2(customObject) ; For example, maybe cooler objects should always enumerate their property store ; as 1, 2, 3 for some reason. class CoolerObject { OwnProps() => [1, 2, 3].__Enum() } </runner> ===== Object References ===== It's important to know that AutoHotkey imagines an object as being separate from any variables that may contain it. Every object has a secret identifying number that acts like a label on a box, called its "pointer". A variable that "contains" an object really just contains that pointer, so that whenever the variable is used AutoHotkey knows where in memory to find the box. Accessing an object whose pointer is contained by a variable is called "referencing" that object, and the object pointer itself is sometimes called "a reference". The object pointer system is an implementation detail that you don't need to worry about //most// of the time, but there are a few common situations where it impacts script behavior. The biggest impact is that when you make a second variable ''B := A'' where ''A'' "contained" an object, you haven't actually copied the //object// but instead copied the object //pointer//. With two copies of the object pointer, you now have two ways to reference the //same object//. If you make changes to the object by referencing it from variable ''B'', those changes will still be present if you reference it from variable ''A''. <runner ahk2> ; Store a reference to a new object in variable A A := Object() ; Duplicate the object pointer into a second variable B := A ; We now have variables A and B that both refer to the same ; object, with some object pointer (#18239 used here as example). ; ; A == #18239 ; \ ; [ Object #18239 ] ; / ; B == #18239 ; If you wanted, you can expose the object pointer with the ; code below however there is little practical reason to do ; this besides debugging. MsgBox "Variable A holds object #" ObjPtr(A) "`n" . "Variable B also holds object #" ObjPtr(B) ; Look inside the object and set the property store ; key `PropertyKey` to the value `"PropertyValueA"` a.PropertyKey := "ValueA" ; This is like the previous line, but because A and B ; both reference the same object, it actually overwrites ; the value that was previously written. b.PropertyKey := "ValueB" ; If you look inside the object, you'll find that whether ; you access it by the reference in A or the reference in B, ; there is only one object and its property store contains ; the value "ValueB". MsgBox "Accessed from variable a: " a.PropertyKey "`n" . "Accessed from variable b: " b.PropertyKey </runner> This behavior is also seen when passing objects as parameters to functions. When you pass an object as a parameter that function receives a copy of the object pointer rather than a copy of the object itself. If that function makes changes to the object those changes are reflected outside of the function as well. <runner ahk2> ChangeValues(someObject, someNumber) { ; Update the object referenced by the copy of the object pointer someObject.propertyKey := 2 ; Update the copy of the number someNumber := 2 } myObject := { propertyKey: 1 } myNumber := 1 MsgBox ( "--- Before ---`n" "myObject.propertyKey: " myObject.propertyKey "`n" "myNumber: " myNumber ) ChangeValues( myObject, ; Pass a copy of the object pointer myNumber ; Pass a copy of the number ) ; myNumber was not modified, but the object referenced by ; myObject was modified. MsgBox ( "--- After ---`n" "myObject.propertyKey: " myObject.propertyKey "`n" "myNumber: " myNumber ) </runner> ===== Fundamentals of Class Objects ===== ==== Function Objects ==== In AutoHotkey v1, there were several global collections of names that were kept separate. There was a collection of command names, a collection of label names, a collection of function names, and a collection of variable names. AutoHotkey v2 has mostly merged these collections, folding them all into the //just// variable name collection. Label-based subroutines have been replaced in favor of functions. Commands have been replaced in favor of functions. And, critically, functions have been redesigned to all be stored //inside// global variables. Allowing functions to be saved inside variables and passed around like data is known as having [[https://en.wikipedia.org/wiki/First-class_function|first-class functions]]. In AutoHotkey, it is achieved by using [[https://www.autohotkey.com/docs/v2/misc/Functor.htm|function objects]], which are objects that can run code when you use the call syntax: ''name()''. Both user-defined functions and built-in functions are implemented this way, with function definition syntax creating a global variable by the function's name to hold the function object. <runner ahk2> MyFunction() { ; No matter how this function is called, the message box ; will say "You called MyFunction". MsgBox "You called " A_ThisFunc } MsgBox IsObject(MsgBox) ", " Type(MsgBox) MsgBox IsObject(MyFunction) ", " Type(MyFunction) MyVar := MyFunction ; Put MyFunction into a different variable MyVar() ; Call the function object stored inside MyVar </runner> Function objects come inside global read-only variables by default, but can be passed around just like any other object. As shown above, it's easy to put the function object into a different variable even if the new variable has a different name. Additionally, AutoHotkey allows you to //skip// defining the global read-only variable by defining some functions directly inside an expression: <runner ahk2> MyVar := () => MsgBox("You called '" A_ThisFunc "' (the arrow function)") MyVar() ; In AHKv2.1 this is allowed as well: ;MyVar2 := () { ; MsgBox "You called '" A_ThisFunc "' (the function expression)" ;} ;MyVar2() </runner> By itself, this syntax is usually seen when defining OnEvent type callbacks. It allows you to skip defining a function that might only be called in one place: <code autohotkey> CloseCallback() { MsgBox "You tried to close the GUI" } g := Gui() g.OnEvent("Close", CloseCallback) ; Can be rewritten as: g := Gui() g.OnEvent("Close", () => MsgBox("You tried to close the GUI")) ; Or in v2.1: g := Gui() g.OnEvent("Close", () { MsgBox "You tried to close the GUI" }) </code> However, where things start to get really interesting is when you put function objects into //other objects//. Just like a function object can be stored inside a regular variable and then that variable becomes callable, a function object can be stored as an object property and then that property becomes callable. A callable property on an object is called a //method//. When you call a function stored as an object property, AutoHotkey does a little trick with the parameter list. If you have ''MyObject'' with a property ''FunctionProperty'' that contains a function object, calling ''MyObject.FunctionProperty(1, 2, 3)'' will automatically translate into (roughly) ''Temp := MyObject.FunctionProperty'' then ''Temp(MyObject, 1, 2, 3)'', where ''Temp(...)'' behaves as a regular call to the function. You see, the object that contains the property is passed as a first parameter to the function. <runner ahk2> MyFunction(this, a, b, c) { MsgBox 'a: ' a '`nb: ' b '`nc: ' c } MyObject := { FunctionProperty: MyFunction } ; These following 4 lines are all equivalent MyObject.FunctionProperty(1, 2, 3) Temp := MyObject.FunctionProperty, Temp(MyObject, 1, 2, 3) (MyObject.FunctionProperty)(MyObject, 1, 2, 3) MyObject.FunctionProperty.Call(MyObject, 1, 2, 3) </runner> ==== Prototyping ==== AutoHotkey objects are *prototype* based, but AutoHotkey's docs don't really do a proper job of explaining what that means or how it works. Prototype-based Object-Oriented-Programming (OOP) is a way of arranging objects containing function objects so that the emergent behavior is similar to non-prototype OOP languages (think C++ or Java). The first part of this arrangement was //function objects// being nested inside regular objects. The second part is //prototyping//. Prototyping is the generic term for allowing one object to borrow the properties of another object (the //prototype// object). In AutoHotkey, this is achieved using the "base" mechanism. By adding a base to your object, whenever you try to access a property on your object that does not exist AutoHotkey will then check the base object to see if it exists there instead. <runner ahk2> baseObject := { someProperty: "alpha" } testObject := { base: baseObject } MsgBox testObject.someProperty ; Will show "alpha" </runner> ==== Class Syntax ==== AutoHotkey's ''class'' syntax is so-called [[https://en.wikipedia.org/wiki/Syntactic_sugar|sugar syntax]]. Sugar syntax is an easier to read and write shorthand for code that is too verbose to work with directly. The implication of calling class syntax as sugar syntax is that you can do almost everything that the ''class'' keyword does entirely without using it. There are a few minor exceptions that we will go over later. Class syntax is used to simultaneously define two things: a "prototype object" and a "class object". A prototype object is used the *base* object for class instances. When you create an object like ''myObject := MyClass()'', the value of ''myObject'' ends up looking something like ''myObject := {base: MyClass.Prototype}''. The prototype object is the object that holds all the method functions that you can call on the class instance. Remembering the fundamental of how functions stored in objects are called, it would mean that in this following example, when ''testMethod'' is called the value of ''this'' will be equal to ''myObject'' //not// ''MyClass.Prototype''. <runner ahk2> testMethod(this, a, b, c) { MsgBox "this Ptr: " ObjPtr(this) MsgBox 'a: ' a '`nb: ' b '`nc: ' c } MyClass := { Prototype: { functionProperty: testMethod } } myObject := {base: MyClass.Prototype} MsgBox "Prototype Ptr: " ObjPtr(MyClass.Prototype) MsgBox "myObject Ptr: " ObjPtr(myObject) myObject.functionProperty(1, 2, 3) </runner> The "class object" created by class syntax starts pretty simple: an object with a ''Prototype'' field. But then AHK adds onto that with an "instance factory". Instance factory is a term that I don't think the AHK docs ever uses, but it really should because that's what it would be called in any sane language. An instance factory is a function that creates instances of a class. An instance factory for an AHK class works something like this: <code autohotkey> classFactory(someClass) { instance := {base: someClass.Prototype} instance.__Init() if HasMethod(instance, "__New") { instance.__New() } return instance } </code> The instance factory gets put onto the class object as its "Call" method. With the class factory put onto the class object like this, you can create instances by calling the class object directly: <runner ahk2> testMethod(this, a, b, c) { MsgBox 'a: ' a '`nb: ' b '`nc: ' c } classFactory(someClass) { instance := {base: someClass.Prototype} instance.__Init() if HasMethod(instance, "__New") { instance.__New() } return instance } MyClass := { Prototype: { functionProperty: testMethod }, Call: classFactory } myInstance := MyClass() myInstance.functionProperty("alpha", "bravo", "charlie") </runner> This code invokes "Call" automatically, like ''(MyClass.Call)(MyClass)'', which invokes ''classFactory'' and returns the instance object. That's the vast majority of what class syntax does. In that last example, we manually created this class: <runner ahk2> class MyClass { functionProperty(a, b, c) { MsgBox 'a: ' a '`nb: ' b '`nc: ' c } } myInstance := MyClass() myInstance.functionProperty("alpha", "bravo", "charlie") </runner> When defining a class, it allows you to specify static and non-static properties. You can do exactly the same with the manually written code. Static properties get added to the class object. Non-static properties get added to the instance by the ''%%__Init%%'' method called by the instance factory: <runner ahk2> class MyClass1 { static someProp := 123 someProp := 456 } myInstance1 := MyClass1() MsgBox "Static " MyClass1.someProp " | Non-Static: " myInstance1.someProp ; Equivalent to classFactory(someClass) { instance := {base: someClass.Prototype} instance.__Init() if HasMethod(instance, "__New") { instance.__New() } return instance } MyClass2 := { Prototype: { __Init: (this) => (this.someProp := 456) }, Call: classFactory, someProp: 123 } myInstance2 := MyClass2() MsgBox "Static " MyClass2.someProp " | Non-Static: " myInstance2.someProp </runner> === Unique behavior === As mentioned previously, there are a few unique features of the ''class'' syntax that are not easily replicated. The first is //definition hoisting//. Definition hoisting is the ability to define a class (or other construct) //below// the point where it will be referenced. This allows you to write a class definition at the bottom of your script, but still use it in the auto-execution section. Function definitions are also hoisted in this way. The second difference is that the variable defined using ''class'' syntax to hold the class object is made read-only. If you define a class manually like any other object, that class name can be overwritten later. But if you define it with ''class'' syntax, trying to overwrite the global variable that holds the class object will result in the exception "This Class cannot be used as an output variable."