Navigation: Language Reference > 3 - Variable Declarations > Special Data Types > ====== Reference Variables ====== | |
A reference variable contains a reference to another data declaration (its “target”). You declare a reference variable by prepending an ampersand (&) to the data type of its target (such as, &BYTE, &FILE, &LONG, etc.) or by declaring an ANY variable. Depending upon the target's data type, the reference variable may contain the target's memory address, or a more complex internal data structure (describing the location and type of target data).
Valid reference variable declarations:
&BYTE | &SHORT | &USHORT | &LONG | &ULONG | &DATE | &TIME |
&REAL | &SREAL | &BFLOAT8 | &BFLOAT4 | &DECIMAL | &PDECIMAL | &STRING |
&CSTRING | &PSTRING | &GROUP | &QUEUE | &FILE | &KEY | &BLOB |
&VIEW | &WINDOW | ANY | &USTRING | &BSTRING | &VARIANT |
The &STRING, &CSTRING, &PSTRING, &DECIMAL, and &PDECIMAL declarations do not require length parameters, since all the necessary information about the specific target data item is contained in the reference itself. This means a &STRING reference variable may contain a reference to any length STRING variable.
A reference variable declared as &WINDOW can target an APPLICATION, WINDOW, or REPORT structure. References to these structures are internally treated as the same by the Clarion runtime library.
An ANY variable can contain a reference to any of the simple data types, and so, is equivalent to any of the above except &GROUP, &QUEUE, &FILE, &KEY, &BLOB, &VIEW, and &WINDOW.
Procedure Reference Variables
Clarion 11.13622 Sept. 4, 2020 - FEATURE: Reference variables of Procedure types are supported by the compiler, and corresponding support is added to the linker and RTL. For more see Clarion Sharp Blog post on August 25, 2020.
Reference Assignment
The &= operator executes a reference assignment statement (destination &= source) to assign the source's reference to the destination reference variable. You may also use a reference assignment statement in conditional expressions.
The NULL built-in variable is used to “un-reference” a reference variable or to detect an “un-referenced” reference variable in a conditional expression.
Reference Variable Usage
The label of a reference variable is syntactically correct every place in executable code where its target is allowed. This means that, any statement that takes the label of a WINDOW as a parameter can also take the label of an &WINDOW reference variable which has been reference-assigned a WINDOW structure.
When used in a code statement, the reference variable is automatically “dereferenced” to supply the statement with the value of its target. The only exception is reference assignment statements, when the reference assigns the reference to the data item it is referencing. For example:
Var1 LONG !Var1 is a LONG RefVar1 &LONG !RefVar1 is a reference to a LONG RefVar2 &LONG !RefVar2 is also a reference to a LONG CODE RefVar1 &= Var1 !RefVar1 now references Var1 RefVar2 &= RefVar1 !RefVar2 now also references Var1 RefVar1 &= NULL !RefVar1 now references nothing
Reference Variable Declarations
Reference variables may not be declared within FILE or VIEW structures, but they may be declared within GROUP, QUEUE, and CLASS structures. Issuing CLEAR(StructureName) for a GROUP, QUEUE, or CLASS structure containing a reference variable is equivalent to reference assigning NULL to the reference variable.
Global references cross thread boundaries, and so, may be used to reference data items in other execution threads.
A reference variable used in any attribute of a control, field, WINDOW or REPORT declaration must receive its value (i.e., a reference to some typed allocated storage) before processing this declaration on enter to the scope where it is declared. For example, if a WINDOW is declared in a procedure, the reference variable can be declared and receive its value before entry into the procedure, or be declared in the same procedure before the WINDOW and receive its value in the constructor of some class declared before the WINDOW.
Named QUEUE and CLASS References
In addition to the data types listed above, you may also have references to “named” QUEUEs (&QueueName) and to named CLASSes (&ClassName). This allows you to use references to pass “named group” parameters, which allow the receiving procedure access to the component fields of the named structure.
A reference to a named QUEUE or CLASS may be a “forward reference.” That is, the named QUEUE or CLASS does not have to have been declared previous to the reference variable declaration which “points at” it. However, the forward reference must be resolved before the reference variable can be used. In the case where the reference variable is contained within a CLASS declaration, the forward reference must be resolved before the object is instantiated, else the reference will be blank and unusable.
There are several advantages to using forward references. You can have a QUEUE of object references which each contains a reference to a QUEUE of object references which each contains a reference to a QUEUE of object references … For example, you could create a queue of siblings within a CLASS structure like this:
FamilyQ QUEUE Sibling &FamilyClass !A forward reference END FamilyClass CLASS Family &FamilyQ ! END
Another advantage is the ability to truly “hide” the targets of PRIVATE references in CLASS declarations. For example:
!An include file (MyFile.inc) contains: WidgetManager CLASS,TYPE WidgetList &WidgetQ,PRIVATE ! DoSomething PROCEDURE END !Another file (MyFile.CLW) contains: MEMBER('MyApp') INCLUDE('MyFile.INC') WidgetQ QUEUE,TYPE Widget STRING(40) WidgetNumber LONG END MyWidget WidgetManager !Actual instantiation must follow ! forward reference resolution MyWidget.DoSomething PROCEDURE CODE SELF.WidgetList &= NEW(WidgetQ) !Valid code SELF.WidgetList.Widget = 'Widget One' SELF.WidgetList.WidgetNumber = 1 ADD(SELF.WidgetList)
In this example, references to SELF.WidgetList are valid only within the MyFile.CLW file. Example:
App1 APPLICATION('Hello') END App2 APPLICATION('Buenos Dias') END AppRef &WINDOW !Reference to an APPLICATION, WINDOW, or REPORT Animal CLASS Feed PROCEDURE(SHORT amount),VIRTUAL Die PROCEDURE Age LONG Weight LONG END Carnivore CLASS(Animal),TYPE Feed PROCEDURE(Animal) END Cat CLASS(Carnivore) Feed PROCEDURE(SHORT amount),VIRTUAL Potty BYTE END Bird Animal !Instance of an Animal CLASS AnimalRef &Animal !Reference to an Animal CLASS CODE IF CTL:Language = 'Spanish' !If spanish language user AppRef &= App2 ! reference spanish application frame ELSE AppRef &= App1 ! else reference english application frame END OPEN(AppRef) !Open the referenced application frame window IF SomeCondition AnimalRef &= Cat !Reference the Cat ELSE AnimalRef &= Bird !Reference the Bird END AnimalRef.Feed(10) !Feed whatever is referenced
In Clarion.NET, we have removed the requirement to use & to declare a reference to an object in the data section. See the New in Clarion# topic for more information.
See Also: