All Scheme objects, regarless of their Scheme type, are represented as instances of the type Object in C. Object is implemented as a small C struct in newer Elk releases and was an integral type earlier. However, code using Elk should not assume a specific representation, as it may change again in future revisions. An Object consists of three components:
Elk defines a few macros to retrieve and modify the fields of an Object independent of its representation:
TYPE(obj) ISCONST(obj) SET(obj,t,ptr) POINTER(obj) SETCONST(obj)
TYPE() returns the contents of the type field of an Object; POINTER() returns the contents of the pointer field as an unsigned long (different macros are provided for types which have their values stored directly in the Object rather than in the heap); ISCONST() returns the value of the const bit; and SETCONST() sets the const bit to 1 (it cannot be cleared once it has been set). ISCONST() and SETCONST() may only be applied to Objects that have their value stored on the heap (such as vectors, strings, etc.); all other types of Scheme objects are ipso facto read-only. Another macro, SET(), can be used to set both the type and pointer field of a new object.
Two objects can be compared by means of the macro EQ(), which is also used as the basis for the Scheme predicate eq?:
EQ(obj1,obj2)
For each predefined Scheme type, there exists a preprocessor symbol that expands to the integer value of that type (the contents of the type field of members of the type). The name of each such symbol is the name of the type with the prefix ``T_'':
T_Boolean T_Pair T_Vector etc...
if (TYPE(obj) == T_Vector) ...
CHAR(obj)
VECTOR(obj)
int i, num = VECTOR(obj)->size; for (i = 0; i < num; i++) VECTOR(obj)->data[i] = ...;
struct S_Pair { Object car, cdr; };
#define VECTOR(obj) ((struct S_Vector *)POINTER(obj)) #define PAIR(obj) ((struct S_Pair *)POINTER(obj))
Authors of Scheme extensions and Elk-based applications are encouraged to follow these conventions in their code and, for each new type xyz, store the new type value (which is allocated by the interpreter when the type is registered) in a variable T_Xyz, and define a structure or class S_Xyz, and a macro XYZ() that makes a pointer to this structure from a member of the type. Capitalization may vary according to personal preference.