3.4 Invariants and rulesets

In performing object-oriented analysis and building a model, a large number of lessons can be learnt from AI systems built using semantic nets and from semantic data modelling. Specifications that exhibit encapsulation of attributes and operations are all very well but do not necessarily contain the meaning intended by the analyst or the user. To reuse the specification of an object we should be able to read from it what it knows (attributes), what it does (operations), why it does it and how it is related to other objects' interfaces. It is our position that this semantic content is partly contained in the structures of association, classification, composition and usage and by the assertions, invariants and rulesets which describe the behaviour.

The fact is that all semantics limit reuse, although they make it safer. For example, inheritance does so; and so does anything that makes the meaning of an object more specific. In system specification, both aspects are equally important and the trade-off must be well understood and managed with care, depending on the goals of the analysts and their clients.

One must also be aware of the need to decide whether rules belong to individual operations or to the object as a whole. There is no principled reason why operations cannot be expressed in a rule-based language. However, the distinction to be made here is not between the form of expression but the content of the rules. Rules that relate several operations do not belong within those operations and rules which define dependencies between attributes also refer to the object as a whole. Conversely, rules that concern the encapsulated state of the object belong within one of its operations. The most important kind of 'whole object' rules are control rules which describe the behaviour of the object as it participates in structures that it belongs to: rules to control the handling of defaults, multiple inheritance, exceptions and general associations with other objects.

The introduction of encapsulated rulesets was a novel aspect of SOMA. It enhances object models by adding a set of rulesets to each object. Thus, while an object is normally thought to consist of Identifier, Attributes and Operations, a SOMA object consists of Identifier, Attributes, Operations and Rulesets. Rulesets are composed of an unordered set of assertions and rules of either 'if/then' or 'when/then' form. This modelling extension has a number of interesting consequences, the most remarkable of which is that these objects - which are local entities - can encapsulate the rules for global system behaviour; rather as DNA is supposed to encapsulate the morpheme. A further consequence is that objects with rulesets can be regarded as intelligent agents for expert systems developments.

It is widely agreed that it is quite insufficient to specify only the attributes and operations (the signature) of an object. To specify the object completely we must say how these are allowed to interact with each other and what rules and constraints must be obeyed by the object as a whole to maintain its integrity as such. Some languages, such as Eiffel, and some methods, such as BON, Catalysis or Syntropy, achieve a partial solution by using assertions. Assertions in such systems are of two kinds: assertions about the operations and assertions about the whole object. The former are typically pre- and post-conditions while the latter are called class invariants. SOMA and Catalysis add invariance conditions to the operational assertions and SOMA generalizes class invariants to rulesets - which can be chained together to infer new information. There are also assertion facets representing attribute constraints. Here are the definitions:

Attribute assertions

Operational assertions

The facets of an operation may include more than one assertion of any of these types. Assertions may be represented by state-transition diagrams as we shall see.

The normal assumption behind the above definitions is that the logic to be used is standard first order predicate calculus (FOPC). We make no such assumption although FOPC is the usual default logic. Other logics that can be used include temporal, fuzzy, deontic, epistemic and non-monotonic logic. Each ruleset in a class determines its own logic locally, although it would be unusual to mix logics in the same class.

We have already seen the distinction between a type and a class: a type has no implementation. We can now distinguish between types and interfaces. An interface is a list of the messages that can be sent to an object with their parameters and return types. Depending on the interpretation, this may include the get and set operations on attributes. This concept is sometimes referred to as the signature of a type. A type on the other hand is a full specification including all the assertions that may be made about the type and its instances and all rulesets.

Figure 19 Cyclic associations suggest invariants.

An invariant, or constraint, is a single rule that is always obeyed by the object whose scope it lies in. It is expressed using the vocabulary provided by the type model. Example invariants for an airline management system might include: 'Every pilot must be the captain or co-pilot of up to one flight per day', 'The captain and co-pilot cannot be the same person' or 'Every flight must be flown by a captain who is qualified for this plane type'. Clearly, the invariant of a type can refer to the public interfaces of other types. Invariants can be expressed informally, as above, or using the high precision of OCL or other formal logic systems.

One possible source of invariants is the existence of cycles in type diagrams. In fact, as we shall see later, any bi-directional association usually requires a pair of invariants - precisely because the pair of rôlenames is a loop. In Figure 19 we can see that all the indicated loops may possibly imply the need for one or more invariants to be stated.

For example, in the upper diagram the pilot of a flight must work for the airline that provides the flight. The reader is encouraged to write invariants for the other cycle in Figure 19.

Rulesets generalize class invariants and permit objects to do several things:

Rules specify second order information, such as dependencies between attributes; for example, a dependency between the age of an employee and her holiday entitlement. Global pre- and post-conditions that apply to all operations may be specified as rules. A typical business rule in a human resources application might include 'change holiday entitlement to six weeks when service exceeds five years' as a rule in the Employee type. With rulesets the notation can cope with analysis problems where an active database is envisaged as the target environment.

Rules and invariants are used to make an object's semantics explicit and visible. This helps with the description of information that would normally reside in a repository, such as business rules for the enterprise. It can also help with inter-operability at quite a low level. For example, if I have an object which computes cube roots, as a client of that object it is not enough to know its operations alone; I need to know that what is returned is a cube root and not a square root. In this simple case the solution is obvious because we can characterize the cube root uniquely with one simple rule: the response times itself twice is equal to the parameter sent. If this rule is part of the interface then all other systems and system components can see the meaning of the object from its interface alone, removing thus some of the complexities of repository technology by shifting it into the object model.

The rules which appear in the rule window may be classified into several, not necessarily exclusive, types, as follows.

Control rules

The last application of rulesets is by far and away the most esoteric. Object-oriented methods must obviously deal with multiple class inheritance. This extension must include provision for annotating the handling of conflict arising when the same attribute or operation is inherited differently from two parent objects. Of course, types compose monotonically so this problem doesn't arise. This kind of discrimination can only be done with a class. One way to deal with it is to use rulesets to disambiguate multiple inheritance. One can then also define priority rules for defaults and demons. (A demon is a method that wakes up when needed; i.e. when a value changes, or is added or deleted.) That is, these rules can determine how to resolve the conflict that arises when an attribute inherits two different values or perhaps specify whether the default value should be applied before or after inheritance takes place or before or after a demon fires. They may also specify the relative priorities of inheritance and demons. As with attributes and operations, the interface of the object only displays the name of a ruleset. In the case of a backward chaining ruleset this might well include the name of the value being sought: its goal; e.g. If Route: needed SEEK Route:

Control rules are encapsulated within objects, instead of being declared globally. They may also be inherited and overridden (although the rules for this may be slightly complicated in some cases - see (Wills, 1991)). The benefit of this is that local variations in control strategy are possible. Furthermore, the analyst may inspect the impact of the control structure on every object - using a browser perhaps - and does not have to annotate convoluted diagrams to describe the local effects of global control. Genuinely global rules can be contained in a top level object, called something like 'object', and will be inherited by all objects that do not override them. Alternatively, we can set up global rules in a special 'policy blackboard' object. Relevant classes register interest in Policies, which broadcasts rule and status changes to registrants as necessary. This uses, of course, a publish and subscribe pattern. Just as state transition diagrams may be used to describe the procedural semantics of operations, so decision trees may be found useful in describing complex sets of rules.

Control rules concern the operations and attributes of the object they belong to. They do not concern themselves. Thus, they cannot help with the determination of how to resolve a multiple inheritance conflict between rulesets or other control strategy problem related to rulesets. This would require a set of metarules to be encapsulated and these too would require a meta-language. This quickly leads to an infinite regress. Therefore multiple inheritance of rules does not permit conflict resolution. A dot notation is used to duplicate any rulesets with the same name. Thus, if an object inherits rulesets called POLICYA from two superclasses, X and Y, they are inherited separately as X.POLICYA and Y.POLICYA. The case of fuzzy rules is slightly different since fuzzy rules cannot contradict each other as explained in Appendix A. Therefore multiply inherited fuzzy rulesets with the same name may be merged. In both the crisp and fuzzy cases, however, the careful user of the method should decide every case on its merits, since the equivalent naming of the inherited rulesets could have been erroneous.

It is sometimes possible, in simple cases, to specify rules that must be obeyed by all control strategies for multiple inheritance. In the case where objects are identified with only abstract data types - i.e. constructed types representing relations, say, are not permitted - we have a clear set of three rules for inheritance:

  1. There must be no cycles of the form: x is AKO y is AKO z is AKO x. This rule eliminates redundant objects.

  2. The bottom of an AKO link must be a subtype, and the top must be a subtype or an abstract type (i.e. not a printable object; not an attribute).

  3. It must be possible to name a subtype of two supertypes. This rule prevents absurd objects, such as the class of all people who are also toys.

These rules are commended as design checks.

Rule chaining

Rule-based systems are non-procedural. That is, the ordering of a set of rules does not affect their interpretation. Rules may be grouped into rulesets which concern the derivation of values for one object. In some environments, such as KEE, rules are each bona fide objects, but this approach begs the question of the relationship of a rule to another object. Most expert systems shells and environments encourage the developer to write the rules first and only later identify the objects used by the rules. This enforces a top-down approach and can be useful as a discipline but contradicts an object-oriented approach.

Figure 21 Qualified association.

In UML we can write invariants and rulesets in an (optional) fourth named compartment underneath the operations compartment of a type icon.

Rule-based extensions to object-oriented analysis help enrich the semantics of models of conventional commercial systems. This makes these models more readable and more reversible; more of the analysts' intentions are evident in the model. This provides a truly object-oriented approach to the specification of advanced database and knowledge-based systems.

As we have seen, control rules are not the only rules in an application. We have mentioned business rules already. In both cases, encapsulating these rules in objects makes sense and enhances reusability and extensibility. System-wide rules belong in the most general objects in the system; i.e. the top of the hierarchy (or hierarchies if there is no catch-all class as there is with Smalltalk's 'object'). They are propagated to other parts of the system via inheritance. All kinds of rule are stored in the rulesets of the optional fourth window of the object icon.

Some researchers have applied this kind of rule-based idea to program browsers. These researchers believe that developers know much about their code that cannot be expressed formally which leads to time being wasted searching for implicit relationships. They suggest that the code should be related to a descriptive level that can be searched and manipulated. For example, the CogBrow research system supports operations such as: 'Find all the routines written last week by J. Smith and change every occurrence of GOTO 32767 to GOTO END:'. Similarly assertions and rules can be manipulated as if they were at the descriptive level. There have also been attempts to apply objects with rules to object-oriented network modelling (Bapat, 1994).

It may be enlightening to know that we were first motivated to add rules to the Coad/Yourdon method in 1989 when using it, not to describe a computer system, but to build a model of an organization. This kind of activity, known these days as enterprise modelling or business process re-engineering, brings to the fore the need to record business rules, often expressed at a high level or vaguely - just the sort of thing knowledge-based systems builders are used to.