[Next] [Previous] [Up] [Top] [Contents]

CHAPTER 6

6.5 Detecting Side Effects

There are those who believe that in an ideal world functions should not have side effects, and that programmers should avoid them at all costs [Abelson and Sussman, 1980]. The world is far from ideal, and, regardless of that, purely functional programming is actually more complicated and difficult to understand when dealing with real programming problems. Studies show that, unlike what is taught in undergraduate computer science curricula everywhere, most industry software applications must deal with inter-process communication, parallelism, and persistent data [Curtis, Iscoe, and Krasner, 1988]. The functional paradigm does not account for these concepts readily.

Object-oriented programming, in a pure sense, requires side effects. Access to slots of an object can only come from methods that are attached to the object. Other methods must go through these accessor methods to read or change a slot.

There can be two kinds of "direct" side effects in a method: a change to a global variable, and any sort of output. A third kind of side-effect is a call to a method that has a side effect. In this case, the side effect does not actually occur within the calling method, yet a side effect will occur when the calling method itself is invoked, so it can be important to discover it.

A change to a global variable occurs whenever that variable appears in an assignment statement as the variable to be changed. In the code level ontology only slots are global variables. All other variables are local to the code-block in which they are defined. Slots are global in the sense that their values are persistent between invocations of a method and calls to other methods, though they cannot be accessed from methods of different objects.

The code-level ontology contains a fairly simple extension which can automatically detect global variable change side effects and calls to methods with side effects. Output methods must be specifically identified as such in order that calls to them may be recognized. This is not really a problem, since output functions are generally part of a support library which would be provided to any developer.


The extension begins with a new part of the code-level taxonomy, shown in Figure 6.12. This new taxonomy of primitive concepts fits under the software-thing concept.[2]

Next, any individual of assignment whose changes role is filled with an individual of slot is a side effect - a slot assignment side effect. A new defined concept for recognizing slot assignment side effects is now added to the ontology that says precisely this:

(cl-define-concept 'slot-assignment-side-effect
                   '(and assignment
                     (all changes slot)))

With this addition to the KBEDS CSIS, all assignment statements that change a slot will be automatically be reclassified under this concept. In order to put these assignment statements into the side effects taxonomy shown in Figure 6.12, a description rule (see Section 2.2.4.1) is added:

This rule tells Classic that every individual of slot-assignment-side-effect is also an individual of direct-side-effect. This rule is required because if the relationship it specifies were part of the defined concept, being a direct-side-effect would become a sufficient condition for recognizing slot assignment side effects, and they would never be found automatically. In other words, the rule says "once a slot assignment side effect is recognized, it should be also be classified as a direct side effect", whereas putting direct-side-effect after assignment in the defined concept definition would say, "A slot assignment side effect must already be known to be a direct side effect to be recognized." The latter is not productive.

At this point we have classified all assignments that change slots as slot assignment side effects and direct side effects. The next addition is a set of roles that will help identify the methods that contain these side effects: has-direct-side-effect, its inverse direct-side-effect-of, and their parents has-side-effect and side-effect-of. With these roles defined, the following path rule is added:


In other words, the direct-side-effect-of role should be filled with the value in the implementation-of role of the assignment. Through the role hierarchy, this also adds the side-effect-of role, and through the inverse, the individual of method that fills this role gets the has-direct-side-effect and has-side-effect roles pointing back to the assignment, as shown in Figure 6.13. With these inverse roles filled in, we can create a new defined concept to recognize methods with side effects:

(cl-define-concept 'method-with-side-effects
                   '(and method
                     (at-least 1 has-side-effects)))

and a more specific one for methods with direct side effects:

(cl-define-concept 'method-with-direct-side-effects
                   '(and method
                     (at-least 1 has-direct-side-effects)))

Note that Classic will automatically classify the second concept under the first, so that need not be told. Now, as a result of the rules that added the has-side-effect links, every method that has in its implementation a slot assignment side effect will have at least one filler in its has-direct-side-effects role, and will be classified as a method with direct side effects.

That may seem like a long chain of inference, but it's not even over yet. The next thing to do is be able to recognize messages that invoke methods with side effects as indirect side effects. Adding another defined concept will do the trick:

(cl-define-concept 'message-side-effect
                   '(and message
                     (all call-method method-with-side-effects)))
Individuals of this new concept can be recognized since all methods with side effects have been found with the previous two defined concepts. A simple description rule will link these message side effects back into the side effect taxonomy:


Next we define two more roles: has-indirect-side-effect and its inverse indirect-side-effect-of, and make them children of has-side-effect and side-effect-of, resp. Once these roles have been defined, and the message side effects have been found, we can identify all the methods that have them in a similar manner to slot assignment side effects. First, create a rule:

which will fill in roles, as in the example shown in Figure 6.14. Now we identify all these methods with indirect side-effects with the defined concept:

(cl-define-concept 'method-with-indirect-side-effects
                   '(and method
                     (at-least 1 has-indirect-side-effects)))
Again, Classic will automatically classify this concept under method-with-side-effects, since the only difference between them is a restriction on a more specific role (has-side-effects in method-with-side-effects, and has-indirect-side-effects in method-with-indirect-side-effects).


The final step is simply to link methods with side effects into the side effect taxonomy with one last description rule:

The addition of this rule basically creates the side effect taxonomy shown in Figure 6.15. The dashed lines indicate that Classic has derived that one concept is subsumed by another, while the solid lines indicate this has been told.

Some of the concepts are not actually classified by classic in this manner, but individuals are effectively put into this taxonomy through the description rules. In other words, Classic does not classify slot-assignment-side-effect under direct-side-effect, but the rule on page 144 that says all individuals of the former concept are also individuals of the latter creates an implicit taxonomy.

The inferences described in this chapter for finding side effects are clearly very deep, yet the developer or maintainer need not be aware of them. In fact, every role involved in this process that needs to be closed for an inference to take place is done so automatically by having at-most restrictions on them. The role implementation-of, for example, can have no more than one filler, so as soon as it gets one, it is closed. All these side effect inferences come with no extra work by the developer or maintainer at all. In addition, while complex to explain, the power of the representation shows itself again in the simplicity of the total code required to add the side effect facility. This code is shown in Appendix F.

6.5.1 Viewing Side Effects

The CSIS menu in the KBEDS CSIS contains two items for viewing side effects, one for viewing direct side effects, and one for viewing methods with side effects. The LISP code, as usual, for these functions is quite simple. For viewing methods with side effects, the following function pops up an individual selection window (an example is shown in Figure 4.16 on page 97) displaying all the methods defined in the system that have side effects:

(defun find-all-methods-with-side-effects ()
  (popup-inds-list (cl-concept-instances (cl-named-concept 'method-with-side-effects))))

The maintainer can then view any one of these methods further.

For viewing all the actions that cause direct side effects, the following simple function pops up an individual selection window displaying all the assignment statements in the system that change a slot:

(defun find-all-side-effects ()
  (popup-inds-list (cl-concept-instances (cl-named-concept 'side-effect))))

Again, the user can view any one of these further.

The power of the representation is clear in the simplicity of all the different functions for generating views. It should be clear that fairly little effort is involved to provide a new views if a maintainer finds that a particular view is desirable and used frequently.


Chris Welty - Dissertation - 17 SEP 1996
[Next] [Previous] [Up] [Top] [Contents]

Generated with Harlequin WebMaker