Specifying types with SYM and PTR
When declaring variables to hold the SYM of a variable or function, it is possible to more accurately describe what the SYM is of. This enables the kc compiler to provide better error checking at compile rather than run-time. Thus a function parameter that needs to be the SYM of a string array could be declared as such and if the programmer tries to call the function with the SYM of a numeric variable then a compile-time error will result. These are compile time declarations and there is no runtime support for these types though they make the code more self documenting.
Similarly in FLD definitions for DEFSTRUCT for fields that will hold pointers to dynamically allocated objects, PTR is used in an analogous way to SYM. More generally PTR is used to type any numeric variable holding the result of a NEW.
These typed declarations uses the AS clause followed by any SYM or PTR expression where X is used to represent the value. Thus:
DEFSUB 'Fn1(pNum AS SYM(X))
To take the SYM of a numeric, an expression such as SYM(X) is used. Other expressions are:
DEFSUB 'Fn2(pstrarray AS SYM(X$()))
This specifies that pstrarray should be the sym of a string array.
Records
If the parameter is a string or an array declared to a particular DEFRECORD type then this can also be specified using the record constant, thus:
DEFSUB 'Fn1(p AS SYM(X$_myrec)) DEFSUB 'Fn2(p AS SYM(X$()_myrec))
Note that it is generally preferred to use BYREF rather than SYM.
Structures
When dealing with dynamically allocated objects, DEFSTRUCT structures are used in preference to DEFRECORD records as they can track the memory pools to use. There are two ways to declare pointers to dynamic structures or strings in a structure. One way is to declare them in place but AS PTR as in this example:
DEFSTRUCT myRec
FLD a$ AS PTR
FLD b$_myRec AS PTR
FLD c$100
ENDSTRUCT
In both cases these fields contain numeric values. The first one holds a pointer to a fixed length string and the second hold a pointer to another structure. The third field is a static string that occupies 100 bytes in the structure itself. In both the first two cases they will be initialized to zero when the structure is instantiated and the application can use REDIM or NEW to get a pointer to a dynamic object and assign it to the field as in
LOCAL DIM r$_myRec REDIM FLD(r$.a$) = "Peter" PTROF(r$.b$) = NEW _myRec
You can have KCML automatically allocate dynamic objects when the structure is allocated by using INIT PTR rather than PTR.
DEFSTRUCT myRec
FLD a$10 AS INIT PTR
FLD b$_myRec AS PTR
FLD c$100
ENDSTRUCT
Now when the structure is allocated, the .a$ field will also be allocated and the field will be initialised with its pointer. Note that the .b$ field can't be initialized this way as it would recusively loop.
If the program needs to get the actual pointer for these objects it can use PTROF() to manipulate it as in:
pRec = PTROF(r$.b$) PTROF(r$.b$) = 0
The more general approach to pointer fields is to always declare them as numeric PTR fields and use AS PTR() to type them as in:
DEFSTRUCT myRec
FLD a AS PTR(X$)
FLD b AS PTR(X$_myRec)
FLD c$100
ENDSTRUCT
This is more general, as it can cope with more types, and the pointer is directly exposed, avoiding the need for PTROF(), but it requires the use of NEW and does not support automatic initialization as INIT PTR did.
Objects
The sym of an object variable may be taken using the form SYM(OBJECT var). The declaration is similarly declared as SYM(OBJECT X). Thus:
LOCAL DIM OBJECT a LOCAL DIM pa AS SYM(OBJECT X) pa = SYM(OBJECT a) OBJECT a = SYM(*pa) 'myfn(OBJECT SYM(*pa))
Functions
For functions rather than using X an explicit function name should be used. This allows the compiler to check that the SYM of the function passed in has a compatible parameter list to the function specified, and also that when the SYM is dereferenced to call the function that the parameters are correct.
Using SYM in DEF RECORD
The same range of SYM declarations used in function arguments are also available for the fields in record statements, using an AS or an "=" before the SYM:
DEFRECORD MyRec
FLD pcount = SYM(X)
FLD arec = SYM(X$_arec)
FLD fnptr = SYM('fn1)
END RECORD
CONST
The CONST keyword may be used to specify that the entity pointed to by the SYM may be referenced but not modified. It is not acceptable to assign the SYM of a constant variable to a symvalue not declared as CONST. The following example shows cases where CONST must be used, including fields in a DEF RECORD as these are always CONST.
PUBLIC DEFRECORD MyRecord
FLD AFld
END RECORD
// Both a$ and .AFld will be constant variables in this subroutine
PUBLIC DEFSUB 'MySub(CONST BYREF a$_MyRecord)
'HelperFn(SYM(a$), SYM(.AFld))
END SUB
PRIVATE DEFSUB 'HelperFn(pVar AS SYM(CONST X$_MyRecord), pF AS SYM(CONST .X))
...
END SUB