Karl-Heinz,
(Fox) arrays are a reference type. The variable (either a local or a memory variable) contains a pointer to memory on the heap where the actual array is stored.
If you pass an array variable to a function then the normal behavior is that you
pass a copy of the reference to the function. This copy of the reference points to the same memory location. The same is true for objects.
Resizing the array with a DIM command will therefore resize the original array.
Allocating a new array and assigning it to the copy of the reference would update the pointer in the copy of the reference and the original variable would still point to the old copy.
If you would
pass an array variable by reference then you would be passing a reference to the location where the reference to the array in memory is located. Resizing the array would do the same as when passing the variable by reference.
Allocating a new array would create a new pointer and this pointer would be stored in the original variable, so the 'old array' would no longer be referenced by this variable.
The behavior of functions like APrinters() in FoxPro and their counterpart in X# would of course depend on how these functions are implemented.
If you look at the FoxPro help file it says that the first parameter of Aprinters() is an array name. The example looks like this:
Code: Select all
IF APRINTERS(gaPrinters) > 0
CLEAR && clear the current output window
DISPLAY MEMORY LIKE gaPrinters && show the contents of the array
ELSE
WAIT WINDOW 'No printers found.'
ENDIF
To me this looks like the first parameter is not "a name" (because that would mean that gaPrinters would be passed as a string) but a variable.
This variable is passed without @ sign, so it is passed by value.
If gaPrinters is already an array then it will be resized to match the number of printers found.
The potential problem lies in this line inside the FoxPro help file:
If the array you include does not exist, Visual FoxPro automatically creates the array
If you are compiling with the option to allow "undeclared variables" then it would indeed be possible to pass gaPrinters without declaring it first. But in that case the only thing the APrinters() function could do is allocate a memory variable with the name "gaPrinters" and assign the array to that.
But to do so, the function needs to know the name of the variable(), and normally a compiler would not pass the name of the variable to the function that is called.
The solution that I see for this is now something like this:
1) Declare a special attribute in the X# runtime that will be used to mark functions that need to be told about the parameter names passed to the. For the sake of this message we could call this the PassParameterNamesAttribute
2) Mark the function (in this case APrinters()) with this attribute. That would look something like this:
Code: Select all
[PassParameterNames];
FUNCTION APrinters(aTarget as __FoxArray, nValue := 0 AS LONG, __xsVariableNames__ as STRING[])
RETURN ...
3) Tell the compiler that when a method / function has this attribute then it needs to add an extra argument to the method call that contains the names (if any) of the parameters passed. When an argument is not a variable but an expression (like the literal 0 or 1 for the second parameter of APrinters) then the variable name passed should be an empty string.
A call to Aprinters() like in the example code should then be translated to this by the compiler
Code: Select all
IF APrinters(gaPrinters, 0, <STRING>{"gaPrinters",""}) > 0
Please note that I have not discussed this with the rest of the team, but something like this would work.
Maybe we could change the attribute to contain the name of the parameter that needs his name passed, so the code could look like this, since there is usually only one parameter that needs to pass its name.
Code: Select all
[PassParameterName("aTarget")];
FUNCTION APrinters(aTarget as __FoxArray, nValue := 0 AS LONG, __xsVariableName__ as STRING)
RETURN ...
Robert