AutoIt3 variables and function parameters

Introduction

The AutoIt3 help file does not account for copy-on-write behavior and is in my opinion incorrect in some topics. Do not believe everything you read and test if in doubt. That is what I do and I will try to explain my concerns.

Variables

The code below is declaring variables $a and $b. Then assigning $b to equal $a. $b is then assigned a new value.

Global $a, $b
$a = 5
$b = $a
$b = 10

The line $b = $a above is where $b references the same memory location as $a as copy-on-write has not occurred yet. A copy is not created if the variables are equal, but rather when the write to change the value occurs.

The line $b = 10 above is where $b is allocated a reference to a new memory location. It is at this point when copy-on-write has occurred.

The example above is not perhaps a good one for showing the copy process but rather complete overwrite though it can still be regarded as copy-on-write. Perhaps if I called it ByReference-Until-Write instead. Keep that in mind as ByRef is used in function parameters which I am going to discuss next.

Function parameters

Function parameters are variables that are by value, are actually by reference initially. until change occurs in which creates and references a modified copy. Look at the code example below.

Global $a $a = 5 Test($a) Func Test($b) ; $b references the memory location of $a at this line. No copy or penalty! $b = 10 ; $b references a new memory location on line above as it has changed. New copy here so penalty. EndFunc

$a above is passed to the by value parameter $b. $b references the memory location of $a so it does the same as the previous example of $b = $a though $b is local to the function in the later. At this point, any effect of by value or by reference is irrelevent. It only becomes effective when $b is changed. The line $b = 10 creates the new copy and this is when the so called penalty happens of using more memory consumption.

Below is a by reference version of the code which remains by reference when changed.

Global $a $a = 5 Test($a) Func Test(ByRef $b) ; $b references the memory location of $a at this line. No copy or penalty! $b = 10 ; $b still references the memory location of $a on line above as it has changed. The memory reference of $a has changed to 10. EndFunc

By reference is not affected by copy-on-write when the line of $b = 10 happens. The effect implies that $a = $b which is what by reference does once $b = 10.

*** Function parameters, whether by value, by reference or declared as constant, all of these are initially by reference. ***
The previous statement does not include literals passed as function parameters as I am not sure how AutoIt3 internals handle literals. The statement contradicts the remarks in the AutoIt3 help file. The effect was perhaps invisible at the time of writing the help file as it is handled automatically by the C++ runtime or perhaps the (memory handling) subsystem of the operating system.

Const can be used on a function parameter. When Const is used on the parameter then I see no good reason to also use ByRef on the same parameter as the effect on the parameter will be the same as if it is by value. No copy is done and no penalty is done.

A Const in AutoIt3 is a variable marked as read only and remains as a variable as read only even if compiled. A Const in compiled languages such as C++ may have Const variable declarations removed and the Const variables replaced with the literal values that were assigned to them during compilation. The compile of C++ would follow conditions so what happens to one variable may not happen to another variable. Thus C++ and similar compiled languages can go under the term of optimised compilation. Interpreted languages may not have many of the optimised behaviors that C++ may have so there is always difference to test. On the other side, interpreted languages have features though that C++ can only dream of. Using Const in C++ everywhere as possible is efficiency, in AutoIt3 it just read only variables that can hinder the script if used too much. Example of too much is that if you create many Consts then you may need even more variables to have the same task done. Too much in AutoIt means even more added to memory which creates inefficency and can treat the memory like a garbage dump.

Download test script and results

copy-on-write-test.au3

This script shows the results that any penalty of memory consumption with function parameters is not done until the by value parameter has changed. The script will use up approximately 128 Megabytes. Lower the integer in the array declaration to something less then 26 to use less memory if necessary.

The results I get from the linked script.

Note: Memory stats are in Megabytes 28385 Memory available when empty array declared 28257 Memory available when array is filled with values 128 Memory used by this process Memory State Declaration 0 Same ByRef Const 0 Same ByVal Const 0 Same ByRef 0 Same ByVal 129 Larger ByVal (changed) 2 Same ByVal

As above shows memory usage of the process is approximately the same except for the 2nd last function call which changed the parameter inside the function as it occurs a penalty of creating a copy. If you incurr a penalty for using by value on a function parameter unconditionally, with no change, then it does not show in the test. It is because copy-on-write only happens when a by value parameter is changed. Large variables or Arrays can be passed by reference or by value with no penalty so long as no changes are done to them. A by reference parameter is not a must for large variables or arrays but rather a memory efficient way to handle the data if a change is done.

Func...Return...EndFunc revision

I have revised and modified the topic remarks of Func...Return...EndFunc from the AutoIt3 help file below.

The Const keyword is optional and indicates that the value of the parameter will not change during the execution of the function. A variable declared Const which is passed to a function remains constant in the function only if the parameter is also Const. The ByRef keyword indicates the parameter should be treated as a reference to the original object and any changes will affect the original object. The default behavior is by value which indicates the parameter should be treated as a reference to the original object until change occurs. The change by value creates a copy as a new reference from the original object with the changes done. ByRef is typically preferred when a function expects large amounts of data, such as a large array, where copying all the data would impose a significant performance penalty when a change occurs. Named variables or unnamed temporary variables, such as function return values can be passed to ByRef parameters. If using both keywords ByRef and Const with a function parameter, the order of the keywords is not important, so long as they are both in front of the variable they modify. Using ByRef Const or Const by itself will have the same effect as both reference the original object as change is not allowed due to the use of Const in both cases. Entire arrays can be passed to functions and can be returned from them by simply using the array name without any brackets. Arrays can be passed to user defined functions using the ByRef keyword to avoid the overhead of copying all the data in the array if a change is done to the array. Optional parameters are defined by assigning a default value to them. The value may be a global variable, macro or literal value. Optional parameters always appear last in the function definition. All parameters added after the first optional parameter must also be optional. Inside the function, the number of parameters given when the function was called can be retrieved with the @NUMPARAMS macro (see example 2). Use the Return keyword to exit the function. Unlike built-in functions, user-defined functions return 0 unless another return value is specified. Note that function declarations cannot appear inside other function declarations.

Perhaps better clarity could be used though this is what I suggest. This is more correct then the current remarks used.

Func...Return...EndFunc concerns

Some excepts that I did find misleading in the current remarks are below. AutoIt version is placed in the top of the excepts when a difference is encounted.

A variable declared Const can only be passed to a function using a Const parameter.

Incorrect. It can be passed as a not Const parameter though it may not be Const in the function. Note: Same in 3.3.8.1 and 3.3.10.2.

3.3.8.1 The default behavior copies the parameter into a new variable however ByRef links the new variable to the original parameter. 3.3.10.2 By default the parameter is copied into a new variable but ByRef links the new variable to the original.

Incorrect. It does the copy when changed. Refer to copy-on-write. Note: Similar in 3.3.8.1 and 3.3.10.2. Just reworded and still misleading.

ByRef is typically preferred when a function expects large amounts of data, such as a large array, where copying all the data would impose a significant performance penalty.

Incorrect. Just missing the vital information of penalty on change. Refer to copy-on-write. Note: Same in 3.3.8.1 and 3.3.10.2.

3.3.8.1 If using both keywords ByRef and Const with a function parameter, the order of the keywords is not important, so long as they are both in front of the variable they modify. 3.3.10.2 The order of the keywords is not important, as long as they are both in front of the parameter they modify.

Informative yet fail to understand why using both ByRef and Const on a parameter is useful. Using Const on its own should be enough and does the same. Note: Similar in 3.3.8.1 and 3.3.10.2, just reworded. A new line was added in 3.3.10.2 to oppose with my first paragraph line here about using both ByRef and Const as shown below.

3.3.10.2 (new) Declaring parameters as both ByRef and Const is useful when the large original variable must remain unchanged as AutoIt will return an error if the function attempts to alter it inadvertantly.

Incorrect. AutoIt will error with just the use of a Const parameter. This line seems to have been added with intent to promote a lie to cover for a conflict of interest.

Arrays should be passed to user-defined functions using the ByRef keyword to avoid the overhead of copying all the data in the array.

Incorrect. No changes equals no penalty so the mention of should do this is fail. Refer to copy-on-write. Note: Same in 3.3.8.1 and 3.3.10.2.

The missing copy-on-write information is critical for good understanding of using variables and function parameters. Any testing i have done or other scripts used have influenced my statements mentioned here. As I mentioned above, test if in doubt and I ask that you test what I have stated here for confirmation.

Final Notes

Updated to reflect on AutoIt 3.3.10.2. I am disappointed that I witness possible corruption based on the few, or the one. Perhaps some of the detail in the help file was added with lack of knowledge long ago, though rewording and adding more misleading content may imply dishonest behavior. This page was intended as temporary, though now it has even more purpose to remain.

I see some people promoting the use of the Local keyword in Global scope. This is deceptive code that lies in your face and it is nothing but them using influence of corruptive powers to ruin a language and to confuse and divide everyone. What Global or Local does in a Global scope does not excuse the lie. Note: It is Global scope!  I refuse to promote corruption and I will try to promote what I consider as honest coding practices that you can adopt based on your own free will. Forcing code practices under the pretense of "Good Coding Practice" or any other deceptive phrase is what corrupt people will try to do. I have no wish to promote constant abuse promoted by a corrupt few, or the one.

Authored by Michael Heath