|
I-Type Expressions |
|
|
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.
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 @
To simplify editing of compound I-type expressions, the "edit values" mode of both the ED and SED editors can be used to break the expression such that each element appears on a separate line.
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. |