[Icon home]

Icon External Values

Carl Sturtivant
Computer Science & Engineering Department
University of Minnesota

Gregg M. Townsend
Department of Computer Science
The University of Arizona

www.cs.arizona.edu/icon/v950/extlvals.htm
Last updated March 14, 2008

Introduction

The loadfunc function links C code from a dynamic library so it can be called by an Icon program. The C code must implement the particular interface expected by Icon. This facility is described in Icon Analyst 36 and is available on all current platforms. Some examples are found in the cfuncs and packs/loadfuncs directories of the Icon program library.

External values provide a way for data created by C code to be stored and transferred within an Icon program. This allows state to be maintained across multiple calls of external functions.

The creation of an external value in C defines not just the data itself but also some related attributes. These control the sorting behavior, image, and other such aspects. Icon provides defaults and also adds a serial number similar to those of lists, sets, and tables.

The specification of attributes effectively creates a number of distinct types. Each external library can define the types it needs for its own purposes. From an object-oriented perspective, these can be seen as subtypes of a common external type.

External Values in an Icon Program

External values are opaque to Icon. They are created only by dynamically loaded C functions, any of which in turn may have access to their internals. In this way a library of Icon functions to work with a specific kind of external value is possible. However, such values can be seen and manipulated (assigned, passed to procedures or functions, sorted, copied, etc.) in Icon. The behavior of an external value in Icon may be modified to some extent by the implementation of the dynamically loaded function that is used to create it, as described below.

In what follows let E, E1, and E2 be external values produced by some external function or functions. Icon prescribes the following default behavior of such values, which is exhibited if the functions that created them did not override such at the time of creation. Otherwise behavior in the following contexts is determined by the external values' creators.

External values always sort after values of all other types, and this cannot be overridden by the creators of such values. Within themselves external values are first sorted by type name (which is a set by the creator, is returned by the Icon function 'type' and specifies a subtype of the external type). The default sort within such a subtype is by serial number. Only sorting within a subtype (i.e., externals with a specific type name) can be overridden by the creator. See the next section for a description of the relevant C internals. The default behavior follows.

type(E)
returns the string "external"
image(E)
returns a string indicating the type, serial number, and the hexadecimal value of the first or only data word e.g. "external_3(67A04F35)"
copy(E)
returns E itself without copying
sort()
external values sort first by type name and then by serial number
E1 === E2
produces E1 when E1 and E2 are the same external object; otherwise fails
E1 ~=== E2
produces E2 when E1 and E2 are distinct; otherwise fails

Creating and Using External Values in C

These next sections describe the C interface for a reader who is familiar with the use of external functions.

An Icon external value is implemented by a descriptor that points to an external block containing several components. The data area and the function list are the most important of these.

An integer word count indicates the size of the data area. This is specified when the external block is created. Often external data is a single pointer (handle) and so only one word is required. The content of the first word of the data block is used in the default image, as described in the previous section.

The function list allows the programmer to override, at the granularity of each individual data value, the default behaviors listed in the previous section. The list is a callback table pointing to programmer-defined C functions as described in more detail below. The function list also acts as a unique type identifier, because external values with different function lists behave as values of distinct type.

A dynamically loaded C function allocates an external value by including ipl/cfuncs/icall.h and calling alcexternal:

external_block *alcexternal(size_t size, word *data, function_list *funcs)
Allocates and returns a pointer to an external block where size specifies the number of bytes in the entire external block (and by implication the number of words in the data block inside it) and funcs specifies the location of the function list (described in detail in the next section). If funcs is NULL, the external value will exhibit default behavior.

The words pointed to by data are successively copied into the data block until the latter is full. This might typically be called as

blk = alcexternal(sizeof(external_block) + n * sizeof(word), data, funcs);
The result is returned to Icon by the macro call RetExternal(blk). The block may eventually be freed by garbage collection if it is not saved or if it later becomes inaccessable to the Icon program.

A more complete example is found in the file ipl/cfuncs/external.c.

The Function List Passed to alcexternal

The function list is reminiscent of a "dispatch table" or "class pointer" for dynamic method calls in an implementation of an object oriented programming language. Indeed an Icon external value is very much like a traditional object with its own data and methods. Typically such a function list would be static and shared among many Icon external values of the same kind ("class" or "type").

If the programmer does not wish to override any of the default Icon behavior, then there may be no function block, represented by passing NULL to alcexternal. If the programmer desires not to override a particular behavior, then a NULL may be incorporated into the function list in the appropriate place instead of a valid function pointer. The Icon run-time system will then automatically call the corresponding default function when necessary.

The type function_list is a struct with entries for pointers to functions of the following prototypes. These programmer-defined functions replace the default behavior described earlier in this document. In all cases argv is a pointer to one (usually) or two (for extcmp) external values associated with this function list, and argc is 1 or 2 respectively.

descriptor extcmp(int argc, descriptor *argv)
extcmp returns an Icon integer for use in sorting two external values that both have this function list and are therefore considered to be of the same external subtype. The function result should be negative if the first external value is deemed less than the second, zero if they are deemed equal, and positive if the first is deemed greater than the second. This overrides the default behavior of the sort function which compares serial numbers.
descriptor extcopy(int argc, descriptor *argv)
extcopy returns an external value defined as a copy of its argument. This overrides the default behavior of the copy function, which is to return another reference to the external value without copying.
descriptor extname(int argc, descriptor *argv)
extname returns an Icon string naming the type of the external value. This overrides the default behavior of the type function, and thus also affects the ordering relative to other external values when sorting.
descriptor extimage(int argc, descriptor *argv)
extimage returns an Icon string to serve as the image of the external value. This overrides the default behavior of the image function.

Implementation Details

This section supplements the Icon implementation book.

A descriptor of the external type has a vword containing the bit pattern D_External which contains the bits T_External indicating the external type, along with the bit F_Nqual indicating that the value is not a string and the bit F_Ptr indicating to the garbage collector that the dword is a pointer that needs tending. The dword contains a pointer to an external_block. This block is implemented as a C struct with a pointer to a function_block C struct as follows. The types word and descriptor are defined in ipl/cfuncs/icall.h.

typedef struct function_list { /* list of user defined callbacks */
	descriptor (*extcmp)   (int argc, descriptor *argv);
	descriptor (*extcopy)  (int argc, descriptor *argv);
	descriptor (*extname)  (int argc, descriptor *argv);
	descriptor (*extimage) (int argc, descriptor *argv);
} function_block;	

typedef struct b_external {
	word header;		/* the block type */
	size_t size;		/* the number of bytes in the block */
	long id;		/* the serial number */
	function_list *funcs;	/* pointer to the callback list */
	word data[1];		/* words of custom data, may be more than 1 */
} external_block;

A call of alcexternal initializes all fields of an external block. Data is copied without interpretation, and the function list pointer is stored. The header is assigned an appropriate constant for the garbage collector, and the size is set. alcexternal maintains a static count of the number of external_blocks allocated, and this is incremented and assigned to id.

The following error code numbers are assigned for use with external values:

errnoerrtextmeaning
131external expected not an external value
132incorrect external type external of wrong flavor
133invalid external value right flavor in wrong context
134malformed external value data is bogus, not just inappropriate