version 2004.1 (Modified)
Pointers provide an advanced way (in programming) to refer to data.
When you use the language, you access various objectsin particular, tables, fields, variables, and arraysby simply using their names. However, it is often useful to refer to these elements and access them without knowing their names. This is what pointers let you do.
The concept behind pointers is not that uncommon in everyday life. You often refer to something without knowing its exact identity. For example, you might say to a friend, "Let's go for a ride in your car" instead of "Let's go for a ride in the car with license plate 123ABD." In this case, you are referencing the car with license plate 123ABD by using the phrase "your car." The phrase "car with license plate 123ABD" is like the name of an object, and using the phrase "your car" is like using a pointer to reference the object.
Being able to refer to something without knowing its exact identity is very useful. In fact, your friend could get a new car, and the phrase "your car" would still be accurateit would still be a car and you could still take a ride in it. Pointers work the same way. For example, a pointer could at one time refer to a numeric field called Age, and later refer to a numeric variable called Old Age. In both cases, the pointer references numeric data that could be used in a calculation.
You can use pointers to reference tables, fields, variables, arrays, and array elements. The following table gives an example of each data type:
Object | To Reference | To Use | To Assign |
Table | vpTable:=->[Table] | DEFAULT TABLE(vpTable->) | n/a |
Field | vpField:=->[Table]Field | ALERT(vpField->) | vpField->:="John" |
Variable | vpVar:=->Variable | ALERT(vpVar->) | vpVar->:="John" |
Array | vpArr:=->Array | SORT ARRAY(vpArr->;>) | COPY ARRAY (Arr;vpArr->) |
Array element | vpElem:=->Array{1} | ALERT (vpElem->) | vpElem->:="John" |
Using Pointers: An Example
It is easiest to explain the use of pointers through an example. This example shows how to access a variable through a pointer. We start by creating a variable:
MyVar:="Hello"
MyVar is now a variable containing the string "Hello." We can now create a pointer to MyVar:
MyPointer:=->MyVar
The -> symbol means "get a pointer to." This symbol is formed by a dash followed by a "greater than" sign. In this case, it gets the pointer that references or "points to" MyVar. This pointer is assigned to MyPointer with the assignment operator.
MyPointer is now a variable that contains a pointer to MyVar. MyPointer does not contain "Hello", which is the value in MyVar, but you can use MyPointer to get this value. The following expression returns the value in MyVar:
MyPointer->
In this case, it returns the string "Hello". The -> symbol, when it follows a pointer, references the object pointed to. This is called dereferencing.
It is important to understand that you can use a pointer followed by the -> symbol anywhere that you could have used the object that the pointer points to. This means that you could use the expression MyPointer-> anywhere that you could use the original MyVar variable.
For example, the following line displays an alert box with the word Hello in it:
ALERT(MyPointer->)
You can also use MyPointer to change the data in MyVar. For example, the following statement stores the string "Goodbye" in the variable MyVar:
MyPointer->:="Goodbye"
If you examine the two uses of the expression MyPointer->, you will see that it acts just as if you had used MyVar instead. In summary, the following two lines perform the same actionboth display an alert box containing the current value in the variable MyVar:
ALERT(MyPointer->) ALERT(MyVar)
The following two lines perform the same action both assign the string "Goodbye" to MyVar:
MyPointer->:="Goodbye" MyVar:="Goodbye"
Using Pointers to Buttons
This section describes how to use a pointer to reference a button. A button is (from the language point of view) nothing more than a variable. Although the examples in this section use pointers to reference buttons, the concepts presented here apply to the use of all types of objects that can be referenced by a pointer.
Let's say that you have a number of buttons in your forms that need to be enabled or disabled. Each button has a condition associated with it that is TRUE or FALSE. The condition says whether to disable or enable the button. You could use a test like this each time you need to enable or disable the button:
If (Condition) ` If the condition is TRUE ENABLE BUTTON (MyButton) ` enable the button Else ` Otherwise DISABLE BUTTON (MyButton) ` disable the button End if
You would need to use a similar test for every button you set, with only the name of the button changing. To be more efficient, you could use a pointer to reference each button and then use a subroutine for the test itself.
You must use pointers if you use a subroutine, because you cannot refer to the button's variables in any other way. For example, here is a project method called SET BUTTON, which references a button with a pointer:
` SET BUTTON project method ` SET BUTTON ( Pointer ; Boolean ) ` SET BUTTON ( -> Button ; Enable or Disable ) ` ` $1 Pointer to a button ` $2 Boolean. If TRUE, enable the button. If FALSE, disable the button If ($2) ` If the condition is TRUE ENABLE BUTTON($1->) ` enable the button Else ` Otherwise DISABLE BUTTON($1->) ` disable the button End if
You can call the SET BUTTON project method as follows:
` ... SET BUTTON (->bValidate;True) ` ... SET BUTTON (->bValidate;False) ` ... SET BUTTON (->bValidate;([Employee]Last Name#"") ` ... For ($vlRadioButton;1;20) $vpRadioButton:=Get pointer("r"+String($vlRadioButton)) SET BUTTON ($vpRadioButton;False) End for
Using Pointers to Tables
Anywhere that the language expects to see a table, you can use a dereferenced pointer to the table.
You create a pointer to a table by using a line like this:
TablePtr:=->[anyTable]
You can also get a pointer to a table by using the Table command. For example:
TablePtr:=Table(20)
You can use the dereferenced pointer in commands, like this:
DEFAULT TABLE(TablePtr->)
Using Pointers to Fields
Anywhere that the language expects to see a field, you can use a dereferenced pointer to reference the field. You create a pointer to a field by using a line like this:
FieldPtr:=->[aTable]ThisField
You can also get a pointer to a field by using the Field command. For example:
FieldPtr:=Field(1; 2)
You can use the dereferenced pointer in commands, like this:
FONT(FieldPtr->; "Arial")
Using Pointers to Variables
The example at the beginning of this section illustrates the use of a pointer to a variable:
MyVar:="Hello" MyPointer:=->MyVar
You can use pointers to interprocess, process and, starting with version 2004.1, local variables.
When you use pointers to process or local variables, you must be sure that the variable pointed to is already set when the pointer is used. Keep in mind that local variables are deleted when the method that created them has completed its execution and process variables are deleted at the end of the process that created them. When a pointer calls a variable that no longer exists, this causes a syntax error in interpreted mode (variable not defined) but it can generate a more serious error in compiled mode.
Note about local variables: Pointers to local variables allow you to save process variables in many cases. Pointers to local variables can only be used within the same process.
In the debugger, when you display a pointer to a local variable that has been declared in another method, the original method name is indicated in parentheses, after the pointer. For example, if you write in Method1:
$MyVar:="Hello world" Method2(->$MyVar)
In Method2, the debugger will display $1 as follows:
$1 ->$MyVar (Method1)
The value of $1 will be:
$MyVar (Method1) "Hello world"
Using Pointers to Array Elements
You can create a pointer to an array element. For example, the following lines create an array and assign a pointer to the first array element to a variable called ElemPtr:
ARRAY REAL(anArray; 10) ` Create an array ElemPtr:=->anArray{1} ` Create a pointer to the array element
You could use the dereferenced pointer to assign a value to the element, like this:
ElemPtr->:=8
Using Pointers to Arrays
You can create a pointer to an array. For example, the following lines create an array and assign a pointer to the array to a variable called ArrPtr:
ARRAY REAL(anArray; 10) ` Create an array ArrPtr := ->anArray ` Create a pointer to the array
It is important to understand that the pointer points to the array; it does not point to an element of the array. For example, you can use the dereferenced pointer from the preceding lines like this:
SORT ARRAY(ArrPtr->; >) ` Sort the array
If you need to refer to the fourth element in the array by using the pointer, you do this:
ArrPtr->{4} := 84
Using an Array of Pointers
It is often useful to have an array of pointers that reference a group of related objects.
One example of such a group of objects is a grid of variables in a form. Each variable in the grid is sequentially numbered, for example: Var1,Var2, , Var10. You often need to reference these variables indirectly with a number. If you create an array of pointers, and initialize the pointers to point to each variable, you can then easily reference the variables. For example, to create an array and initialize each element, you could use the following lines:
ARRAY POINTER(apPointers; 10) ` Create an array to hold 10 pointers For ($i; 1; 10) ` Loop once for each variable apPointers{$i}:=Get pointer("Var"+String($i)) ` Initialize the array element End for
The Get pointer function returns a pointer to the named object.
To reference any of the variables, you use the array elements. For example, to fill the variables with the next ten dates (assuming they are variables of the date type), you could use the following lines:
For ($i; 1; 10) ` Loop once for each variable apPointers{$i}->:=Current date+$i ` Assign the dates End for
Setting a Button Using a Pointer
If you have a group of related radio buttons in a form, you often need to set them quickly. It is inefficient to directly reference each one of them by name. Let's say you have a group of radio buttons named Button1, Button2, , Button5.
In a group of radio buttons, only one radio button is on. The number of the radio button that is on can be stored in a numeric field. For example, if the field called [Preferences]Setting contains 3, then Button3 is selected. In your form method, you could use the following code to set the button:
Case of :(Form event=On Load) ` ... Case of : ([Preferences]Setting = 1) Button1:=1 : ([Preferences]Setting = 2) Button2:=1 : ([Preferences]Setting = 3) Button3:=1 : ([Preferences]Setting = 4) Button4:=1 : ([Preferences]Setting = 5) Button5:=1 End case ` ... End case
A separate case must be tested for each radio button. This could be a very long method if you have many radio buttons in your form. Fortunately, you can use pointers to solve this problem. You can use the Get pointer command to return a pointer to a radio button. The following example uses such a pointer to reference the radio button that must be set. Here is the improved code:
Case of :(Form event=On Load) ` ... $vpRadio:=Get pointer("Button"+String([Preferences]Setting)) $vpRadio->:=1 ` ... End case
The number of the set radio button must be stored in the field called [Preferences]Setting. You can do so in the form method for the On Clicked event:
[Preferences]Setting:=Button1+(Button2*2)+(Button3*3)+(Button4*4)+(Button5*5)
Passing Pointers to Methods
You can pass a pointer as a parameter to a method. Inside the method, you can modify the object referenced by the pointer. For example, the following method, TAKE TWO, takes two parameters that are pointers. It changes the object referenced by the first parameter to uppercase characters, and the object referenced by the second parameter to lowercase characters. Here is the method:
` TAKE TWO project method ` $1 Pointer to a string field or variable. Change this to uppercase. ` $2 Pointer to a string field or variable. Change this to lowercase. $1->:=Uppercase($1->) $2->:=Lowercase($2->)
The following line uses the TAKE TWO method to change a field to uppercase characters and to change a variable to lowercase characters:
TAKE TWO (->[My Table]My Field; ->MyVar)
If the field [My Table]My Field contained the string "jones", it would be changed to the string "JONES". If the variable MyVar contained the string "HELLO", it would be changed to the string "hello".
In the TAKE TWO method, and in fact, whenever you use pointers, it is important that the data type of the object being referenced is correct. In the previous example, the pointers must point to an object that contains a string or text.
Pointers to Pointers
If you really like to complicate things, you can use pointers to reference other pointers. Consider this example:
MyVar := "Hello" PointerOne := ->MyVar PointerTwo := ->PointerOne (PointerTwo->)-> := "Goodbye" ALERT((Point Two->)->)
It displays an alert box with the word "Goodbye" in it.
Here is an explanation of each line of the example:
MyVar:="Hello"
This line puts the string "Hello" into the variable MyVar.
PointerOne:=->MyVar
PointerOne now contains a pointer to MyVar.
PointerTwo:=->PointerOne
PointerTwo (a new variable) contains a pointer to PointerOne, which in turn points to MyVar.
(PointerTwo->)->:="Goodbye"
PointerTwo-> references the contents of PointerOne, which in turn references MyVar.
Therefore (PointerTwo->)-> references the contents of MyVar. So in this case, MyVar is assigned "Goodbye".
ALERT ((PointerTwo->)->)
Same thing: PointerTwo-> references the contents of PointerOne, which in turn references MyVar. Therefore (PointerTwo->)-> references the contents of MyVar. So in this case, the alert box displays the contents of myVar.
The following line puts "Hello" into MyVar:
(PointerTwo->)->:="Hello"
The following line gets "Hello" from MyVar and puts it into NewVar:
NewVar:=(PointerTwo->)->
Important: Multiple dereferencing requires parentheses.
See Also
Arrays, Arrays and Pointers, Constants, Control Flow, Data Types, Identifiers, Methods, Operators, Variables.