Introducing Demeter and its Laws

by Brad Appleton

If you hang around any of the object-oriented mailing lists, chat groups, or Usenet newgroups, you'll notice that the name "Demeter" keeps popping up every few months or so on a regular basis. Usually it is in the form of a question asking "What is Demeter?" or "What is the Law of Demeter? Other times it is used in passing as an obscure reference (which usually prompts the earlier questions just stated).

This introduction is intended to give the reader a general introduction to what Demeter is, its concepts and principles, and where to find more detailed information about the Law of Demeter (LoD), the Demeter method, the Demeter project, and Adaptive Programming (AP).

Demeter Origins

The classic "Law of Demeter" refers to a paper that was published in IEEE Software in 1989.

Lieberherr, Karl. J. and Holland, I.
Assuring good style for object-oriented programs
IEEE Software, September 1989, pp 38-48

There are also some other articles about the same time period (1988-89) in various issues of ACM SIGPLAN Notices, usually authored by one or more of Karl Lieberherr, Ian Holland, and Arthur Riel.

For starters, Demeter is a research project at Northeastern University lead by Dr. Karl Lieberherr. I believe there is also work going toward a commercial implementation of the Demeter project. The URL for the Demeter project (its "home page" on the web) is http://www.ccs.neu.edu/research/demeter/. There is also a "Law of Demeter" link from the Demeter home page at http://www.ccs.neu.edu/home/lieber/LoD.html.

Adaptive Programming

The Demeter method and project is about what Lieberherr calls "Adaptive Programming" (abbreviated AP). AP deals with specifying the connections between objects as loosely as possible (this is called "structure-shy" programming). The Demeter system and tools are all about "Adaptive" programming. It is an extension of OOP that attempts wait to bind algorithms to data-structures until as late as possible. A special kind of language supported by the Demeter tools to work with other OOPLs, lets you write "adaptive" programs that try to express things like:

starting from object A, go to object C via all objects with an attribute named "x".

Thus, the precise details about going from A to Z to Q to P to M and then to C, are "distilled" into the above "traversal specification" which tries to represent the essence of what is really required at a more generic level. Hence, if your class hierarchy structure or network changes so that the exact path that was used for the above "access" (A -> Z -> Q -> P -> M -> C) now has changed to encompass new classes or more paths, the actual code for the algorithm or behavior doesn't need to change because the condition of A to C via "x" is still correct. The structure needs to be updated, but not the method implementation.

This is "Adaptive Programming", it makes your programs more flexible, more resilient to change, and more adaptable to varying configurations of classes within a given domain. Lieberherr has written a book on Adaptive programming:

Adaptive Object-Oriented Software: The Demeter Method with Propagation Patterns
by Karl J. Lieberherr; PWS Publishing Company, Boston, 1996, ISBN: 0-534-94602-X

The Law of Demeter

The "Law of Demeter" (or LoD) as it is commonly called, is really more precisely the "Law of Demeter for Functions/Methods" (LoD-F). It is a design-style rule for object-oriented programs. Its essence is the "principle of least knowledge" regarding the object instances used within a method. The idea is to assume as little as possible about the structure and properties of instances and their subparts. Thus, it is okay for me to request a service of an objects instance, but if I reach into that object to access another sub-object and request a service of that sub-object, I am assuming knowledge of the deeper structure of the original object that was made available to me.

The Law of Demeter says that if I need to request a service of an objects sub-part, I should instead make the request of the object itself and let it propagate this request to all relevant sub-parts, thus the object is responsible for knowing its internal make-up instead of the method that uses it. Stated more formally, the Law of Demeter for functions says that:

A method "M" of an object "O" should invoke only the the methods of the following kinds of objects:
  1. itself
  2. its parameters
  3. any objects it creates/instantiates
  4. its direct component objects

The basic idea is to avoid invoking methods of a member object that is returned by another method. When you do this, you make structural assumptions about the container object that may be likely to change. The container may later need to be modified to contain a different number of the contained objects, or it may end up being changed to contain another object which contains the original component object. If the "returned" object isn't a subpart of the object whose method was invoked, nor of some other object, then it typically is not a violation of LoD to invoke a method of the returned object (particularly if the object was created by the invoking method).

Using the Law of Demeter ("LoD") you instead ask the container to invoke a method on its elements and return the result. The details of how the container propagates the message to its elements are encapsulated by the containing object.

A side-effect of this is that if you conform to LoD, while it may quite increase the maintainability and "adaptiveness" of your software system, you also end up having to write lots of little wrapper methods to propagate methods calls to its components (which can add noticeable time and space overhead). This problem is addressed by the Demeter tools, which automate the solution.

There is also a "Law of Demeter for Adaptive Programs" (abbreviated LoD-AP). LoD-AP is a style guideline for how to form your traversal specification. I have also seen some discussion about a Law of Demeter for Strategies (which I believe is on-line at the LoD URL mentioned several paragraphs back). I took a graduate course from Dr. Lieberherr on Demeter. My "term project" developed a Law of Demeter for wrappers (LoD-W) and for propagation patterns (LoD-PP), and devised a metric to indicate the relative "structure-shyness" of a propagation pattern. Anyone interested in a copy of this paper can send me email (its pretty "dry" reading IMHO). Dr. Lieberherr renamed my proposed LoD-W to LoD-AP and re-stated it slightly.

The Demeter Tools

At present, the Demeter tools and method are the subject of many papers and workshops. Demeter tools have been implemented to work with C++, Java, Tcl/Tk, and Perl 5. There are also several design patterns for adaptive programming. The Demeter tools for Java make use of "Adaptive Visitors" objects which are AP analogs of the "Visitor" pattern from the now famous Design Patterns book by the "gang of four" (or GoF): Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides.

The Visitor objects are responsible for carrying out the traversal specification. The Adaptive Visitors are a more seamless fit with OOPLs than a relational-ish graph-navigation-specification language. Before the Adaptive Visitor objects were used, Adaptive C++/Demeter programs looked kind of like SQL-style from-to statements and constraints with embedded C++ code (or vice versa). Now (with Java and adaptive visitors) they look more like a single language rather than two mixed together

AP in general, and the Demeter method and tools, lift object-oriented programming to a higher level of abstraction by allowing the user to focus on the essential classes in a network and the invariants among their relationships.

The Demeter Method

One uses a "class graph" of a system to indicate all the inheritance and containment relationships between objects in the system. The graph can be represented textually as a grammar. If the "grammar" is LL(1) (or can be reduced to an LL(1) grammar -- which is usually the case) then there are lots of nice properties it has that lets the Demeter tools determine and automate all sorts of nice things for you.

Hence, the gist of it is that if you need to code a method that has to navigate (via other methods and/or objects) across several links and intermediate links to process information, then using the Demeter tools, you (the "adaptive programmer") rarely have to concern yourself with knowledge of any objects along the navigation path other than the source and destination classes/vertices and perhaps some (but not all) key intermediate objects/vertices. The Demeter tools can generate all the intermediate navigations from the class graph and your from-to spec (with optional constraints). Later, when your class graph evolves and changes, the code for the method you wrote doesn't need to be modified at all (since you specified it "adaptively" as a propagation pattern using succinct traversal specifications). All you usually need to do is just regenerate the traversal code with Demeter and then recompile.

Object "Waves" and "Particles"

In Physics, sometimes it is useful to view an electron as a particle and other times as a wave. In software, I think the same is true of objects. Sometimes we take the particle view (an object encapsulated by the boundaries of information hiding) and sometimes we take the "wave" view (the set ("wave") of collaborations and collaborators for a given operation). A common deficiency of current OOPLs is that while they provide semantic constructs to minimize dependencies when employing the "particle view", they don't provide semantic constructs to yield the same benefit for the "wave" view. They let us separate interface from implementation within the bounds of a single object or method (the particle view), but not necessarily within the relationships of all of the collaborators for a single method.

The Demeter method and tools address this deficiency. They let us use protocols that specify only the preconditions, postconditions, and invariants not only for a single object method, but also for the entire family of actors that collaborate to carry out the entire "logical operation". Demeter's "succinct traversal specifications" allow us to encode _only_ the source, destination, and key intermediate members (invariants) of an information access (non-trivial data-flow) without having to know about all the non-critical links in the chain. So when the non-critical links come and go (or otherwise "evolve") no manual effort is required to for us to adapt to this change. The traversal invariant still holds, and only the changes to the class graph need to be made. The same codification of behavior still works simply by re-compiling the program using the Demeter tools (no procedural changes were necessary).

The Demeter tools' syntax may seem a bit unsettling at first, but it allows you to get the same or greater functionality by assuming "less" information. The less you have to assume, the less you need to know and depend on. The less you have to know, the simpler things should be. And, of course, the fewer dependencies you have, the more maintainable, reusable, adaptable (and hence durable) your program will be.

So if you have a method that takes a "BigMac" as an argument and needs to access the seeds on the pickles, you don't have to know about the lettuce, onions, and sesame seed bun that are all "on route" to the pickle seeds (much less that there are 2 all beef patties lurking underneath all of that), all you need to know is that a path exists from the BigMac to its pickle seeds. You don't have to know what that path is or exactly how to traverse it, and you don't have to encode that path in your methods. That way when the burger later changes such that the pickles are now on top of the onions instead of the other way around, you don't have to care.

Corollaries to LoD

An interesting article that seems to be related to LoD is in the ROAD section of the November/December 1996 issue of JOOP (Volume 9, No. 7). It is entitled "Building reusable classes for frameworks" by Gary Brown and Peter Forte. The article doesn't actually make any mention of Demeter or LoD but it has a number of guidelines that I think are actually more detailed refinements or applications of LoD.

They present a bunch of design/programming guidelines and rules for writing classes and class libraries to make them into reusable class frameworks (usable by client subclasses as well as "normal" clients). Some of the rules they propose are:

  1. Whenever an object needs to request a service of some other external object, this external service request should be encapsulated in an internal non-public method of the object. This allows derived classes to override the service request with a more specialized one (it is also a use of the GoF Template pattern).

  2. Whenever an object needs to instantiate some other externally associated object, it should do so using a non-public method to perform the instantiation. This allows derived classes to instantiate a more specialized object if needed.

These two are just a sample of some of the "rules" mentioned in the article. Anyway, to me at least, the authors seem to be extending the LoD with corollaries like:

A public method M of a class C should invoke only its own public and private methods, and those of its superclasses. (Any non-public methods should obey LoD.)

There are probably some other corollaries to LoD that can be implied from this article as well.