With the introduction of GFA-BASIC 32 a few new data types were added to the language. This article discusses one of those, the "Pointer To Type" data type.
The GFA-BASIC 32 Help file describes the Pointer a bit cryptic as: " Pointer is a data type to declare variables as pointers.", and then the syntax is given as:
Dim p As [Register] Pointer [To] type
p: pointer variable
type: any data type (Int, String, Double, UDT)
The help file doesn't contain any real faults, but it is hard to speak from a new data type, because "Pointer To Type" doesn't introduce a new data type. Including the Pointer [To] clause in a declaration introduces a variable of the specified Type for which the address is zero. This means that the declaration doesn't allocate memory for the variable, it only enters the variable name and type in the internal GFA-BASIC 32 variable list. An entry in this list contains the variable's name, variable's data type, and the memory location of the allocated memory to store the data. Once a variable is declared and added to the variable list - a process performed during compiling - you can retrieve the type and memory location of the variable at run-time. GFA-BASIC provides various functions to obtain the properties of an element of the variable list. The type of a variable can be obtained using VarType(varname) or TypeName(varname). The VarType() function returns a predefined constant indicating the variable type (basInt, basObject, etc). The TypeName() function gives the type of the variable in plain English. The actual location of the data can be obtained using VarPtr(varname) or its shortcut V:varname. The next example shows the variable properties of an empty string variable str1.
Dim str1 As String
Trace VarType(str1) ' 255
Trace TypeName(str1) ' String
Trace ArrPtr(str1) ' descriptor: 15517488
Trace VarPtr(str1) ' 0 (no string memory allocated)
Next, the declaration of the variable str2 as a "Pointer To String".
Dim str2 As Pointer To String
Trace VarType(str2) ' 255
Trace TypeName(str2) ' String
Trace ArrPtr(str2) ' 0
Trace VarPtr(str2) ' Access Error
As you can see, GFA-BASIC 32 interprets str2 as a normal String variable. In the first example the declaration of str1 leads to the allocation of a string descriptor, but not to the allocation of string memory. The memory address for the string variable in the internal variable list specifies a pointer to a string descriptor, not a memory location for the data (the same is true for arrays and Hash'es). For a string the VarPtr() function obtains the address for the string data from the descriptor, not from the variable list directly. Because of the Pointer To clause in the str2 declaration, there is no pointer to the descriptor entered in the variable list for str2. When the VarPtr() function is applied to str2 it will try to read the string memory from the descriptor, which is isn't available (zero). VarPtr will try to access memory location 0, which, of course, leads to an Access Error.
The str2 string variable is valid and can be used after the str2 - pointer is set to a piece of memory that GFA-BASIC 32 can interpret as a String data type. GFA-BASIC 32 expects the address of a string descriptor in the variable list, so the str2 - "Pointer To String" variable must be assigned a descriptor. But before we can assign it the address of string descriptor we need a descriptor, for instance from another string, so we can make such a reference.
Dim sName As String = "GFA-BASIC 32"
Pointer(str2) = *sName ' assign descriptor address
Here a string sName is declared and initialized. Then the string variable str2 is given a descriptor using the Pointer()= command. The descriptor of sName is obtained using the "*" – address operator, which is the same as ArrPtr(). To assign an address to a pointer variable, GFA-BASIC 32 introduced the Pointer command. As a result, str2 references the same descriptor as sName and the string data of sName can be manipulated through sName as well as through str2. They effectively are the same.
str2 = "New string contents"
Print sName ' prints "New string contents"
In the previous section we learned that a "Pointer To" variable omits memory to store data. This memory must be provided by a different source. Once a portion of memory is available the variable can be assigned the location using the Pointer()= command. The Pointer()= command is specifically meant to give a pointer variable a physical memory address. The Pointer command has the following syntax:
Pointer var = mem_addr%
Pointer(var) = mem_addr%
The parenthesis are optional, but provide a better optical recognition of the meaning of the command. Note that because the Pointer command assigns the variable a memory address, the value right of the assignment operator (the rvalue) will be (implicitly) converted to a 32-bit integer.
The Pointer() function returns the associated memory location of a pointer variable. For a numeric or user-defined variable it will return the address of the data, but for a string, array, or hash it will return the address of the descriptor. The Pointer()= command and Pointer() function are only valid for "Pointer To" variables. They cannot be used to give just any variable a new memory location. For instance, the following is not valid:
Local x%, y% = 2
Pointer(x%) = V:y% ' error
Print Pointer(x%) ' error
A variable can be assigned a new address, or descriptor for that matter, when the declaration contains the Pointer [To] keyword. Even so, the address or descriptor can be obtained using the Pointer() function. Once a pointer variable has been given a memory location, it can be treated as a normal GFA-BASIC 32 variable with the only difference that its associated data pointer can be changed. For a Pointer To String data type, the Pointer() function returns the descriptor address, which is the same as invoking the ArrPtr() function. For other data types Pointer() returns the same address as VarPtr() or V:. In fact, the function Pointer() is a redundant addition to the language and only introduced to be symmetrical to the Pointer()= command.
To understand passing Pointer To variables to subroutines it is important to remember that these variables do have a type, but don't have a memory location. This immediately excludes ByVal passing, because a ByVal variable is a local variable that is implicitly declared and initialized with a copy of the value of the variable passed to the subroutine. Since a Pointer To variable doesn't have associated data, this cannot happen correctly. Where should the data come from that is to be copied to the routine's argument? (Actually, GFA-BASIC 32 bails out at the first access of the local variable, not at the call of the subroutine.) So, you can pass a Pointer To variable only to a ByRef argument. An example:
Local i As Pointer Int
Proc test(ByRef s As Int)
Dim j As Int = 6
Pointer(s) = V:j ' references a stack location!
Pointer(s) = 0 ' de-reference
Another limitation (I don't know if this a feature) , but only Pointer To variables without a descriptor can be passed. This excludes the passing of Pointer To String data type. The following is not allowed:
Local s As Pointer String
Proc test(ByRef s As String)
Note that it isn't allowed to add Pointer To in a subroutine declaration. Although some think so this is documented; it isn't. The following is not allowed:
Proc test(ByRef s As Pointer To String)
Now, is it possible to initialize a Pointer To variable when declaring? As a matter of fact, this is possible indeed. You must specify a numeric value locating a memory address that is to be interpreted as a variable of the type that you specify after Pointer To. For instance:
Dim pi as Pointer Int = $432178 ' allowed
Const addr% = $432178 : Dim pi2 as Pointer Int = addr% ' not allowed
As, you might see, it is hard to know in advance where to find a hard coded memory address. On the other hand I used this construction many times in referencing global variables of the IDE inside a GLL. The exact locations of the global variables are obtained a debugger...
I hope this shines some light on the underlying ideas of the Pointer To "data type".
SH (30 September 2008)