- Introduction to RuleWorks
- Improved Representation
- Improved Matching Capabilities
- Integration and Modularity
- Differences Between RuleWorks and OPS5
- Match Extensions
- Optional Attribute Data Type Restrictions
- Miscellaneous New Features
- Incompatibilities with OPS5
- Obsolescent Features
- Miscellaneous Side-Effects of Modularity
- Other Miscellaneous Incompatibilities
- Known Problems
Introduction to RuleWorks
RuleWorks is a rule-based programming language that represents a large evolutionary step beyond OPS5. Programmers familiar with the public domain OPS5 will find that most of the basic programming concepts remain the same in RuleWorks. There are, however, numerous new features in RuleWorks that are not available in OPS5. Most of these new features fall into one of following categories of improvements: improved representation, improved matching capabilities, and modularity and integration support.
RuleWorks provides an object-oriented data model that enables the creation of hierarchies of abstraction among classes. Within a class hierarchy, membership, attributes, attribute default values, and optional attribute data type restrictions are all inherited. Each attribute can be declared as either scalar or multi-valued (referred to as compound).
In addition, RuleWorks supports two new data types that increase the power of the language and improve the integration with other programming languages. The first new data type is the instance identifier. An instance identifier is a unique handle that is assigned by the system to each object upon creation, and once assigned it can never be modified. This allows the modeling of explicit relationships among objects. The second new data type is the opaque value. An opaque value is a virtual address pointer that enables objects to have explicit relationships to data structures created within other programming languages.
Improved Matching Capabilities
RuleWorks includes numerous new matching features, including the ability to match at arbitrary levels within the class hierarchy, extensions to the functionality of traditional OPS5 predicates, several new scalar predicates, and numerous new predicates for matching compound value attributes.
RuleWorks extends the definition of the set of relational predicates (>, <, =, >=, <=) to allow integers to be compared against floating point values. These same relational predicates can also be used to compare symbols against other symbols using localizable lexicographic ordering. The semantics for value disjunctions has also been extended to allow arbitrary value expressions within the disjunctions.
There are several new scalar predicates:
- An equality predicate, =, that can compare integers and floats. It can also compare two symbols for equivalence where the case of alphabetic characters is ignored.
- An inequality predicate, -=, that is the inverse of equality.
- A similarity predicate, ~=, that for numbers compares integers or floats for equality within a 1% margin, and among symbols uses the SOUNDEX algorithm to compare phonetic (in English) similarity.
- A dissimilarity predicate, -~=, that matches when the similarity test fails.
There are also numerous new predicates for matching compound attributes:
- Compound attribute values can be compared against other compound values to see if they are identical or not.
- Individual elements within a compound attribute can be compared against scalar value expressions using any of the traditional or new scalar predicates.
- The length of a compound attribute can be compared against any integer value expression using the compound length predicates ([<=], [<>], [<], [=], [>=], [>]).
- A compound attribute can be searched for the presence or absence of a specific value using the containment predicates ([+], [-]).
- A compound attribute can also be searched for the presence or absence of a value that satisfies some scalar predicate by using a containment predicate in conjunction with that scalar predicate.
Integration and Modularity
There are numerous new features in RuleWorks that are designed to support the easy integration of rule-based subprograms into projects that also use traditional languages. There are also several new features designed to make it easier to apply engineering discipline to the creation of rule-based systems and subprograms.
Unlike other rule-based languages, the primary output from a RuleWorks source module is one or more rule-based subroutines. These rule-based subroutines can be called from traditional language code, or from other rule-based subroutines. Rule-based subroutines can directly call subroutines written in other languages, or other rule-based subroutines. A rule-based subroutine can even call itself recursively. This allows rule-based subroutines to be easily embedded into larger systems, and makes them indistinguishable on the outside from subroutines written in other languages.
In addition to rule-based subroutines, RuleWorks provides some other modularity features. RuleWorks gives programmers, for the first time, the ability to explicitly control not only the functional interfaces among subroutines, but also the implicit interfaces associated with matchable objects among multiple rule-based subroutines. Using these new features, it is now possible for a programmer to write multiple independent rule-based subsystems that are guaranteed not to interfere with each other. It is also possible for multiple rule-based subsystems to share all matchable objects with each other, or to share only a specific subset of the matchable objects that each can access.
These new modularity features include:
- Support for modular callable rule-based subprograms through the following constructs:
- Control of the access to matchable data through the DECLARATION-BLOCK construct.
- Support for calling out to subroutines written in any language via the EXTERNAL-ROUTINE declaration, including the automatic conversion of argument data types as necessary.
- Support for explicit actions to take place under specific control-related situations:
+ ON-ENTRY construct
+ ON-EMPTY construct
+ ON-EVERY construct
+ ON-EXIT construct
- A new application programmer interface (API) that permits programmers in other languages to access and change objects in working memory.
- Control over the inclusion of and activation of the command interpreter via the following constructs:
Differences Between RuleWorks and OPS5
OPS5 tools include many but not all of the features available within RuleWorks.
There are two major differences and numerous minor differences.
The first major difference is that RuleWorks,
makes no attempt to be 100% compatible with the public domain OPS5.
Constructs like LITERALIZE, LITVAL, and VECTOR-ATTRIBUTE are not available in RuleWorks.
The second major difference is that OPS5 provides none of the modularity features that RuleWorks provides.
For RuleWorks the compatibility goal is to allow rules from an OPS5 program (that did not use obsolescent features)
to be used within a RuleWorks program with no changes.
Several new matching features have been added, including:
- Variables and other value expressions are now evaluated within a value disjunctions, including variables bound in other condition elements.
- Relational predicates (>, <, >=, <=, =) can compare integers versus floats, and symbols versus symbols using localizable lexicographic ordering.
- New similarity predicate, ~=, that for numbers compares integers and floats for equality within a 1% margin, and for symbols uses the SOUNDEX algorithm to compare phonetic (in English) similarity.
- New dissimilarity predicate, -~=, that matches when the similarity test fails.
- Comparisons of compound attributes and a COMPOUND function are now supported.
- The containment and non-containment predicates can now be applied to scalar attributes, as long as the argument to the predicate is a compound value (e.g. ^name [+] <name-list>). In addition, You can now use the containment and non-containment predicates in conjunction with a scalar predicate. This allows you to specify the test to be performed between a scalar value or attribute and each element of a compound attribute or value. Previously, the containment tests were always for identity.
Optional Attribute Data Type Restrictions
Optional attribute data types allow you to restrict the domain of an attribute to a specific type of value. The set of supported domain restrictions are: INTEGER, SYMBOL, FLOAT, OPAQUE, and INSTANCE-ID. If the INSTANCE-ID domain is specified, then a specific class may optionally be identified by stating: INSTANCE-ID OF <class>.
^employees COMPOUND INSTANCE-ID OF employee
^salaries COMPOUND FLOAT)
You are not required to supply attribute domain restrictions. If you do, however, the compiler (and if necessary, the run-time system) rigorously enforces those restrictions.
The PPCLASS command shows any domain restrictions along with the class's attributes.
Miscellaneous New Features
Other new features include:
- GET function (for RHS only) for retrieving arbitrary attribute values from arbitrary instances. (NOTE: GET can be used with unmatched objects. Unmatched objects are objects that were not in the firing instantiation. For example, a variable bound to the ^foo attribute, if it was an instance identifier, would be an unmatched object.)
- Unmatched objects can now be acted upon by the REMOVE, COPY, MODIFY, and SPECIALIZE actions. The compiler gives an informational message (and generates extra run-time checking code) whenever it is unable to verify that the instance argument passed to one of these actions is indeed a valid instance identifier of an existing object.
- The extra-name argument to all the API routines that accept class names is now used. If supplied the extra-name should be the name of the block where the class was declared. This allows independent rule subprograms to each have a class defined that happen to have the same class name.
- Two new special atoms; one for each of the new types: the null Instance-id, #0, and the null Opaque value, %x0 (equivalent to C's NULL).
- IS-OPEN function for checking if a file stream is open. It accepts a file-id. Returns OUT or IN if open, NIL if not.
- EVERY function (for RHS only) for collecting all known instances of a class. Accepts a class name, returns a compound atom of instance-id's.
- MAX/MIN functions used for finding the largest or smallest value.
- SUBSYMBOL function for extracting a segment of a symbol.
- SYMBOL-LENGTH function for counting the characters in a symbol. Accepts a symbolic value, returns an integer.
- IF...THEN...ELSE... and WHILE...DO... actions, provide conditional control over RHS actions.
- REMOVE-EVERY action provides a means to delete objects by class.
Incompatibilities with OPS5
This section describes incompatible differences between RuleWorks and OPS5.
None of the features described as obsolescent are implemented in RuleWorks.
If you have any questions about these features, consult the migration guide.
Obsolete features in RuleWorks include:
- Value disjunctions or variables in the class position in a CE
- LITERAL, LITVAL, and LITERALIZE
- SUBSTR and VECTOR-ATTRIBUTE
Miscellaneous Side-Effects of Modularity
The following differences between OPS5 and RuleWorks are side-effects of the new modularity features:
- An ENTRY-BLOCK (or DECLARATION-BLOCK, or RULE-BLOCK) construct and an END-BLOCK construct are now required as wrappers around all other constructs.
- There is a new compiler command with a completely new set of compiler qualifiers.
- There is now no negated refraction. The new refraction semantics are simply: "Within an invocation of an entry-block, once an instantiation has fired, that specific instantiation will never fire again."
- An instantiation of a rule is the rule plus the objects it matched in its positive condition elements plus the time-tags of those objects. Thus if any of those objects is modified or removed then that instantiation ceases to exist.
- MEA is now the default conflict resolution strategy.
- The conflict resolution strategy can only be set at compile time as an ENTRY-BLOCK qualifier, so there is now no STRATEGY command. An ENTRY-BLOCK checks when it starts up that each RULE-BLOCK it activates has the same strategy as it does.
- There is no RUN action, where in OPS5 it is allowed only in the STARTUP. By default, an entry-block always starts running. The appearance of the command interpreter can now be controlled by the programmer using the DEBUG compiler command qualifier, the DEBUG action, and the rul_debug API routine.
This is unlike OPS5 where source code changes would have to be made to control the interpreter's appearance.
- Because the same entry-block can now be invoked multiple times recursively, when a rule instantiation is fired, it is not actually removed from the conflict set, even though it ceases to be visible there. If you are watching CS changes, be warned that you may see a fired instantiation leaving the conflict set long after it ceased to be visible via the CS command.
- There is no ^C handler in the interpreter, as this could interfere with a user-supplied handler.
- Direct instances of the class $ROOT cannot be created in RuleWorks because of the data modularity.
- The name MAIN (or |main|), when used as an entry block name without an ACCEPTS clause or a RETURNS clause for the ENTRY-BLOCK creates a C compliant entry point named "main" by automatically adding a return type of long.
Other Miscellaneous Incompatibilities
- Disjunctions of condition elements are not supported in this version of RuleWorks.
- As a result of the introduction of the new semantics for the relational predicates, the predicate = (now called the equality predicate), is no longer equivalent to the implied identity predicate, and it cannot bind an unbound variable.
- External-routines names are not allowed to be the same as actions or construct types.
- Rules, catchers, or classes cannot have names that are predicate operators or non-symbolic values.
- The output from PPWM, WM, and TRACE ON WM now shows the readforms of all attribute values, instead of the printforms. The output from WRITE still shows the printforms.
- The syntax for many of the debugging commands has changed. Using the old syntax now generates a syntax error but also usage and example messages.
This section explains problems with the documentation and the software that have been reported but not yet fixed.
- On all platforms except OpenVMS, if you use the -error or the -output compiler qualifiers with a file name that does not have a file extension, RuleWorks does not add the appropriate extension.
- Within RULEs, ON- statements, and CATCHers, if you have a RETURN or a QUIT action nested within any of the control construct actions (e.g. IF, WHILE, FOR-EACH, and SQL-FOR-EACH) and followed by additional actions, then the compiler fails to warn you that those following actions can never be reached.
- When removing an explicit RBREAK, EBREAK, or WBREAK by name or pattern, the interpreter does not complain if there was no such break set.