Law Of Demeter Is Too Restrictive

[Moved from LawOfDemeter]

Here is an argument that states that the LawOfDemeter is too restrictive. The reason is that intermediate values are necessary and therefore the LawOfDemeter gets broken in almost every single interesting method.
You can't call a method on an object that you got from another call!?!? This would seem to greatly limit what you can do with objects, all objects being gotten from calls of one sort or another. If you can't call methods on objects, what can you do?

Smalltalk code like this

 | tokens |
 tokens := parseTree tokens.
 tokens isEmpty ifTrue: [...].

is a violation of the law, because the method ifTrue: is being invoked on the boolean object that was created somewhere else (in the isEmpty: method). Is this because ifTrue: wouldn't be considered a method in another language?

Following the LoD, you'd extract a method ifEmpty:, similar to the commonly needed ifNil:. However, these methods are never actually implemented in practice, because tests like {isEmpty, isString, isWritable} ifTrue:ifFalse: are better implemented through polymorphism, like the NullObject pattern suggests. However, this would require e.g. morphing an EmptyCollection? to a FilledCollection? and back again every now and then. Changing an object's behavior is an expensive operation in Smalltalk. Also, how would one handle things like
 aCollection size > 4 ifTrue: ...
that also break the LoD?

It's hard to give a good suggestion without more code. Like, what does the magic 4 signify? What about
 aCollection ifFull: ...
 aCollection checkIfFull.
? This requires you to use your own classes, of course, and not any standard collection objects.

According to the law, code like "anArray[12].method()" should not be allowed because "anArray" is an object, "operator[]" is itself a method, so the line calls a method on an object it got from another call. Yet such code is very common, and unproblematic, in real life.

The examples of containers such as arrays aren't really violations of Demeter. Container classes -- which Demeter refers to as "Repetition" objects because their purpose is to contain 0, 1, or more other objects -- don't encapsulate knowledge of the existence of their containees. In fact, that knowledge is the point of their existence, and relying on that knowledge doesn't introduce any dangerous coupling since the interface of a container class isn't likely to change in the future.

Instead, container classes encapsulate the implementation details of how the contained objects are stored and accessed. So assuming knowledge of members in a container isn't a structural assumption about the container, and it doesn't violate Demeter.

The Demeter system considers Repetition objects as special classes of objects for which the oft-quoted normal Demeter "law" does not apply in the same manner. In fact, the Demeter method/system contains several laws/forms of Demeter, each of which applies to its appropriate context (which is still admittedly broad and abstract) and is not completely universal in applicability. People just tend to hear only about the form that is most commonly cited and not always with the appropriate context. Even so, for regular OOD/OOP, it's still more of a guideline (a very strong recommendation) rather than a hard and fast, inviolable rule.

BradAppleton, KeithDevens, MarkSwanson

The complaint about collections is easily handled by treating a variable holding a collection as a multi-valued variable for purposes of evaluating adherence to the Law. The question is, for this class, how many classes can break this one if they change? The Law limits the potential damage to one hop away. Without the Law, exponents rear their ugly heads.

I guess this is in response to RonJeffries' comment above. I don't deny that you example code is bad (not a reflection on the author :-), but this is also in violation of the "law", though it seems fine to me:
 tokens isEmpty ifTrue: [...]
-- AnthonyLander

The above may have a special case embedded there: It is OK to pass through objects whose types are immutable. Meaning that you cannot change the interface to an array, or to a Boolean. The structure is widely (universally?) known and does not affect the surrounding structure. It is safe to make assumptions about the structure of such types.

-- PeterSumskas

How to apply the LawOfDemeter successfully

I've had success applying the Law of Demeter by allowing exceptions for three kinds of class: So, in my code the Law of Demeter only applies to ReferenceObjects that embody domain knowledge. This has been very successful in making code easy to read, easy to test and easy to change. The use of automatic refactoring tools helps a great deal with the "easy to change" aspect, so I'm not sure how well this would work in a more manual coding environment. --NatPryce

The Law makes it harder to factor interfaces.

Maybe someone who agrees with the law can explain it so that I'll agree with it too? -- DaveHarris

Why it makes it harder?
See TellDontAsk for a reduced scope and a lot less limiting form of the LawOfDemeter.

View edit of November 21, 2004 or FindPage with title or text search