.c	Saturday  June 4,1983  15:57  LQ+1D.13H.28M.24S.  -*- Bolio -*-


.chapter "NIL Extended Data-Types"

This chapter describes the implementation of the lan{nil} extended
data type (or just term_i{extend}) facility.  This is the stuff from
which flavors and closures are built.  It is not necessary to read
this chapter to make normal and efficient use of flavors or
structures;  rather, this is presented for the curious, and those who
may need such information to interface flavors or structures to
non-lan{lisp} code.  It makes no attempt to fully explain the
implementation of flavors and type inheritance using this.

It is not clear why I am documenting this here. 

.section "The Extend Structure"

lan{Nil} has about 20 primitive data types, which are differentiated
by the type bits in the pointer.  One of these types is named
3si:extend*.  When 3typep* encounters this type, rather than
just returning its name, it looks further.  Implementationally, an
3extend* is structured similar to a simple general vector;  it is
effectively just such a vector, 2except* that it has an extra
header slot in which the term_i{flavor object} is stored.  (This is
what used to be called the term_i{class} of the object.)  This
is a structured object (itself an instance of a flavor), which
describes the type.  Different extends of identical types will have
the same (3eq*) flavor objects.

.defun flavor-of object
This is the primitive which finds the flavor object of 2any*
lan{lisp} object.  If 2object* is an extend, then the flavor
object of the extend is returned.  Otherwise, the pointer type of the
object (with a little fudging and hedging) is used to find the flavor
object which is associated with that primitive type.  Thus, this
primitive integrates the primitive types with the extended types.  It
is what is used by 3typep* of one argument (3of-type*), and
even by 3send*.
.end_defun

.defun si:xref extend index
Returns the 2index*th element of 2extend*, which 2must* be
an extend.  This primitive is normally compiled as a call to a
lan{nil} kernel subroutine which will perform type and bounds
checking (but see var_i{compiler:*open-compile-xref-switch},
(compiler:*open-compile-xref-switch-var)).

3si:xref* is usable with 3setf*.
.end_defun

.defun si:%xref extend index
This is an alternate name for 3si:xref*, which is always
inline-coded by the compiler without error checking.  It also is
usable with 3setf*.
.end_defun

.defun si:make-extend size flavor-object &optional initialization
This is the primitive creation functions for extends.  An extend of
size 2size* is created, with a flavor-object of
2flavor-object*.  If 2initialization* is 3nil* or not
specified, then the slots of the created extend are initialized to
3nil*.  Otherwise, 2initialization* must be either a simple
general vector, or another extend, which is 2at least* 2size*
long.  The created extend will have its slots copied from
2initialization*.  3make-instance* uses this to initialize
constant slots from a template extend, as it is substantially faster
than initializing them individually.

Because this is a low-level implementation primitive, no error
checking is performed anywhere.
.end_defun


.section "The Flavor Object"

The flavor object is a structure which describes the type of the
object.  Certain of the components are defined to occur at specific
offsets, for the benefit of the lan{nil} kernel.  Code written in
lan{macro32} inserts the file 7nil$disk:[nil.vm]:clsoff.mix* to
define these offsets (which have prefix 7cls$*).  Some of the
comments and entries in that file are out-of-date, however the slots
named there are a superset of those which are actually used by the
kernel.

The flavor object is a structure of type 3si:flavor*.  The
definition of it is in the file 7nil$disk:[nil.src]flavm.lsp*, and
is somewhat gross and hairy;  this is a result of historical and
bootstrap reasons (it used to be defined without using
3defstruct*).  The accessors which fetch components of this
structure have names such as 3si:flavor-type-bits*.  Some of those
of interest in the kernel are:
.table 3 250 250
.item si:flavor-name
The name of this type.
.item si:flavor-types
This is a list of all type names from which this type inherits.
Two-argument 3typep*, when the type-specifier is the name of a
flavor-defined type, looks to see if that type specifier is a member
of the flavor-types of the flavor object of the object.  That is,
.lisp
(typep 2x* 'foo)
.end_lisp
is (when 3foo* is the name of a flavor-type) done by
.lisp
(memq 'foo (si:flavor-types (flavor-of 2x*)))
.end_lisp
The first element of this list is 2always* the name of the type.
.item si:flavor-type-bits
For efficiency reasons, certain non-primitive types are given bit
assignments.  This slot holds a fixnum which has a bit set for each of
those types which this type inherits from.  The types which have such
distinction are some of the numeric and array types.  The official
assignments of these bits are in the file
7nil$disk:[nil.src]flavsetup.lsp*.  The position assignments for
lan{macro32} code (suitable for use with 3bbc*, for instance)
are in the file 7nil$disk:[nil.vm]flvtypes.mix*.
.end_table

