DEFVST is an acronym for "DEFine a Vector-like STructure" All entries in a Vector-like structure are "pointers" (FIXNUMs, LISTs, etc) Future plans call for DEFBST - "DEFine a Bitstring-like STructure", useful where the structure is an interface to some memory block required to be sequential by, say, operating system conventions, or hardware needs. DEFSTRUCT - "DEFine a general STRUCTure" which will be done by composing DEFVST and DEFBST. Vector-like structures are implemented as EXTENDs, which are emulated in maclisp by HUNKs, and on the LISPMachine by 1-dimensional ART-Q arrays; EXTENDs interface to a CLASS system, which in MacLISP interface will be activated at any time when the CLASS system is loaded -- only a skeletal amount of information is necessary in each class of vector-like structures in order to prepare for the link-up. Free (global) variables controlling actions: CONSTRUCTOR-NAMESTRING-PREFIX - constructor name is obtained by concatenating this string with the structure name. SELECTOR-NAMESTRING-STYLE - () ==> selector macro name is same as keyword (variable name). - "xxx" ==> selector macro name gotten by concatenating structure name, "xxx", and keyword. Basic macros: DEFVST for defining a structure SETVST for updating a selected component (and SETF) Also, an interface from DEFSTRUCT has been defined (see its documentation). Additional functions: STRUCT-TYPEP for "structures", returns the given name, and for non-structures, returns (). |defvst-construction/||, |defvst-initialize/||, |defvst-typchk/||, |defvst-construction-1/||, |defvst-selection/||, and |defvst-xref/|| are internal helper functions. Usage is like: (DEFVST SHIP (X-POSITION /: FIXNUM) Y-POSITION (MASS = 1000.) (COST (DAY-HIGH-PRICE)) COLOR ) (SETVST (SHIP-X-POSITION QE2) 109.) or alternatively, (SETF (SHIP-X-POSITION QE2) 109.) since SETF will macroexpand out the component selector, and thus turn into SETVST, on structures references. Also, a set of "options" may be specified by including the structure name in a list: (DEFVST (SHIP ...) ...) currently, only :CONSTRUCTOR and :NO-SELECTOR-MACROS are valid options. Note that "=" is used as a keyword in the component part to mean an initialization form follows; and that a component specification which is just a 2-list is expanded like (
) ==> ( = ) This is done for compatibility of style with the LISPM defstructure. See further notes below for the meaning of the ":" in the default form. The SETVST macro (and SETF) is used in conjunction with DEFVST. The example use of DEFVST "defines" a vector-like structure of 4 components; the generic name of this structure is "SHIP", and the components are identified by the ordering of what are called keywords - X-POSITION, Y-POSITION, MASS, and COLOR. Each "definition" causes the creation of 1) A constructor macro, whose name (normally) is obtained by prefixing the string "CONS-A-" onto the generic name of the structure. (Actually, it gets this prefix string from the variable CONSTRUCTOR-NAMESTRING-PREFIX, so that it can be modified) In the example, this becomes CONS-A-SHIP. The constructor permits installing values into the component slots at instantiation time, which are evaluated from either the (default) forms supplied by the invocation of DEFVST, or from the forms obtained by keyword parameters in the instantiating form. E.g. (CONS-A-BANK DOLLARS (PLUS 300. WALLET) MANAGER '|Jones, J.|) would put the numerical value of 300.+WALLET in the DOLLARS component of a newly-created bank, and install |Jones, J.| as its MANAGER. When the CONSTRUCTOR option is given, the user supplies a specific name for this macro. 2) N selector macros, one for each keyword (which denotes one component slot), which are obtained (normally) by concatenating the generic name, a "-", and the keyword name. (Actually, the middle string is obtained from the value of the variable SELECTOR-NAMESTRING-STYLE, so that it can be modified) In the example, we have SHIP-X-POSITION, SHIP-Y-POSITION, SHIP-MASS, and SHIP-COLOR. 2a: (SHIP-X-POSITION QE2) to obtain the x-coordinate of QE2 2b: (SETVST (SHIP-X-POSITION QE2) 109.) to change the x-coordinate to of QE2 to 109. One interesting facet of the selector macroexpansions is that when done for compilation, the turn into the MacLISP CXR, which can generally be open-coded in one or two instructions. But when expanded during interpretation, the go thru a safety checking function, which assures that a selector created for a SHIP structure is only applied to SHIP structures, and not to other kinds of data, or other structures. When the NO-SELECTOR-MACROS option is given, then these macros, like SHIP-X-POSITION, are not created; this is intended to delete the spurious creation of macros, when another macro package is using DEFVST like a subroutine. 3) An information structure, stored as the STRUCT=INFO property of the generic name symbol. This information has the shape (DEFVST STRUCT=INFO VERSION-NUMBER GENERIC-NAME CONSTRUCTOR-NAME NUMBER-OF-NAMED-COMPONENTS COMPONENT-DEFAULT-INITIALIZATION-LISTS CLASS-SKELETON) The generic name corresponds to the "name" of the structure being defined; in the example, it is BANK. The version number corresponds to a version of "implementation status" for DEFVST -- thus it should be possible to make rather radical changes in the future implementation, while maintain compatibility with previously compiled structures (that means that existing FASL files won't have to be recompiled whenever some change to DEFVST is made). The zero'th element of the initializations is either (), or a 3-list of the key-name, selector-name, and default size for the &REST component - the "block" of unnamed components in the structure. The remaining elements of the initializations are the "initialization lists" for each named component: ( ) ;() initial value, no restrictions ( ) ;no restrictions ( . ) CONSTRAINTS, and INITIAL VALUES Each of the components may be constrained to be a particular type datum, and may be initialized according to the form supplied as default by the call to DEFVST. The syntax for a non-simple component specification is a list with the first element being the key name, the item following the first "=" in the list being a form which is the default form to be evaluated for that component in any creations of instances of that structure, and the element following the first ":" is either a type name or list of type names that restricts any creating instance from supplying an initial value of the wrong type. If a key has a restriction associated with it, but no default initial-value form, then DEFVST picks some default value consistent with the restriction. Consider the example (DEFVST BANK (DOLLARS : (FIXNUM FLONUM MUMBLE)) MANAGER (LIMIT : (FIXNUM FLONUM) = 1000000.0) &REST VAULTS 30.) First, the macro invocation of DEFVST would expand into (EVAL-WHEN (EVAL COMPILE LOAD) (AND (STATUS FEATURE COMPLR) (SPECIAL BANK-CLASS)) (DEFPROP BANK BANK-CLASS CLASS-VAR) (|defvst-initialize/|| 'BANK ;structure name 'CONS-A-BANK ;constructor name 3 ;number of components in each structure '#((VAULTS BANK-VAULTS 36) ;vector of slot information (DOLLARS BANK-DOLLARS 0 FIXNUM FLONUM MUMBLE) (MANAGER BANK-MANAGER) (LIMIT BANK-LIMIT 1000000.0 FIXNUM FLONUM)) 2 ;"generation" number of DEFVST '((DSK JONL) TEST EXAMPL)) ;file being processed when DEFVST expanded (DEFPROP BANK-VAULTS (BANK 4 &REST) SELECTOR) 'BANK) The internal function |defvst-initialize/|| creates the STRUCT=INFO property for BANK, and sets up macro definitions for all the selector names, and for the constructor name; also, a "skeleton" is framed so that all instances may be grouped into a CLASS of such structures. (This information is kept in in the STRUCT=INFO property.) When the CLASS system is actually loaded, the skeletons will be fleshed out to the full degree [ see the documentation on the MacLISP SEND facility, and on the EXTENDed CLASS system]. After that, then, a "simple" creation instance will take default values for all components with either initial value or restriction specifications, and null in the unspecified components; for example (CONS-A-BANK) then yields an instance, which when printed as a VECTOR, is like #( 0 () 1.0E6 () . . . () ) namely, a bank with three named components, and with 30. unnamed components which are accessed as if VAULTS were a vector name. Note that the the function CLASS-OF (and also SI:EXTEND-CLASS-OF) gets the class descriptor for this class of structures, which may be only a "skeleton" when the CLASS system isn't loaded. A more complex example of construction, such as, (CONS-A-BANK DOLLARS (CASEQ VIP (FEDERAL 15.0E9) (SAVINGS-&-LOAN 10.0E6) (MICKEY-MOUSE 1)) MANAGER '|Jones, J.| LIMIT (BANK-DOLLARS CURRENT-CONSTRUCTION) VAULTS 12.) illustrates four points of a creating instance - - (1) keywords paired with initial values are just alternating pairs in the list, and (2) the forms for initial values are substituted into a piece of code output by the macro, so that they are evaluated at instantiation time, and (3) the variable CURRENT-CONSTRUCTION is temporarily bound to the structure being created so that it may be referenced; the installing of initial values happens last. (4) components which are under a restriction, and are not constant (at compile time) must be submitted to dynamic type checking. Notice how this macro-expands -- (LET ((CURRENT-CONSTRUCTION (SI:MAKE-EXTEND 33. BANK-CLASS))) (SETVST (BANK-DOLLARS CURRENT-CONSTRUCTION) (|defvst-typchk/|| (CASEQ VIP (FEDERAL 1.5E+10) (SAVINGS-&-LOAN 10000000.0) (MICKEY-MOUSE 1)) '(FIXNUM FLONUM MUMBLE) 'BANK-DOLLARS)) (SETVST (BANK-LIMIT CURRENT-CONSTRUCTION) (|defvst-typchk/|| (BANK-DOLLARS CURRENT-CONSTRUCTION) '(FIXNUM FLONUM) 'BANK-LIMIT)) CURRENT-CONSTRUCTION) This code might actually not run, since it could stop on a Restriction Violation if the variable VIP does not have a value among FEDERAL, SAVINGS-&-LOAN, MICKEY-MOUSE for then it would turn up a () for the DOLLARS component, which was specified to be restricted to fixnums. Further macro-expansion causes the "SETVST"s to become "SI:XSET"s. In maclisp, SI:XREF becomes CXR, SI:XSET becomes RPLACX, and SI:MAKE-EXTEND becomes MAKHUNK (that is how EXTEND's are emulated there). Neither the EXTEND package nor any runtime CLASS facilities need be loaded in the runtime environment of code which uses structures, since dynamic tests are made before any of these facilites are are used (that is, any facility beyond the MacLISP native HUNK capability).