An I-type dictionary record defines a calculation based on data in the data file records. Once an I-type item is defined, it can be referenced in query processor sentences exactly as though it was a real data field. I-type items are sometimes known as virtual attributes, a term which emphasises the fact that their values are not physically stored in the database.
An I-type dictionary item differs from a D-type item only in that field 1 contains the type code I and field 2 contains the actual calculation to be performed. The remaining fields are the same as in a D-type entry.
Consider a simple stock management system in which each inventory item has two price figures; the price that we paid to buy the item into the shop and the price that we will charge the customer. If these are defined by dictionary items named COST and SELL, we can calculate the profit we make selling an item with a simple I-type expression:
SELL - COST
An I-type expression consists data item names, constants, functions and operators in exactly the same way as a QMBasic expression. Whereas a QMBasic program would refer to variable names, an I-type expression uses field names defined in the file's dictionary. These names may be A, C, D, I or S-type items.
Dictionaries migrated to QM from other environments frequently contain data defining items that have hyphens in their names such as CUST-NO. Applying strict QMBasic expression rules to this name would interpret this as calculating the value of CUST minus NO. To allow names of this form, the I-type compiler treats this as a special case and correctly references the CUST-NO item. If CUST and NO were also defined in the dictionary, they take priority in resolving the expression.
Many of the @variables used by QMBasic are also available in I-types. The following @-variables are specific to I-types though some can be used by QMBasic programs to set up the working environment for the I-type.
Most QMBasic functions are also available in I-type expressions. The following functions are either specific to I-type expressions or modified from their QMBasic form:
Just like a QMBasic program, an I-type must be compiled before it can be used. The query processor will do this automatically though I-types can be compiled explicitly using the COMPILE.DICT (synonym CD) command which compiles one or more I-types in a dictionary. The MODIFY command also provides facilities to compile I-types when they are edited. The object code is stored in the dictionary record though ED and SED both hide it.
Note that where one I-type expression uses the result of another, this is handled by a compile time substitution rather than a run time subroutine call. The implication of this is that, if the inner expression is changed, both must be recompiled. The safest way to ensure that everything is consistent is to use the COMPILE.DICT command to compile the entire dictionary after editing an I-type that might be used in another expression.
A compound I-type has multiple elements separated by semicolons, each of which is evaluated in turn, left to right. The value of the first element is stored in an internal variable named @1, the second in @2, and so on. These variables may be referenced in later elements within the compound I-type. The value of the immediately previous element may also be referred to by the symbol @. The overall value of the I-type is the value of the final expression. QM can nest compound I-types.
Use of compound I-types can simplify complex expressions. For example, we might want to calculate someone's age in whole years from their date of birth. This is actually more complex than it may at first seem because we need to allow for people born on February 29 or performing the calculation on February 29. It might be written as a two stage compound I-type:
OCONV(DATE(), "D4Y") - OCONV(DOB, "D2Y"); IF OCONV(@DATE,"DMD") > OCONV(DOB,"DMD") THEN @ + 1 ELSE @
Working with Dynamic Arrays
The QMBasic language has a large number of functions that work on each element of a multivalued data item in turn. These allow developers to write very elegant solutions to apparently complex tasks without resorting to use of a subroutine with loops. For more details, see Multivalue Functions.
An I-type expression can be prefixed by one or more mode settings separated by semicolons with the same effect as use of these modes in a QMBasic program. The available modes are
Note that for compatibility with the QMBasic compiler, the last of these settings is not a $MODE directive.
$MODE INDEX.OVERLAP;INDEX(TEXT, 'AB', 3)
The I-type compiler does not use the $BASIC.OPTIONS record to set default modes.
An I-type expression that is referenced from another I-type cannot include mode settings.