I've been trying to understand Law of Demeter but there is so much conflicting information and opinions on it, that i decided to read the original research paper (1988) (https://www2.ccs.neu.edu/research/demeter/papers/law-of-demeter/oopsla88-law-of-demeter.pdf) - but i'm very confused by one of the rules in it.
The rules are as follows:
For all classes C, and for all methods M attached to C, all objects to which M sends a message must be
- M’s argument objects, including the self object or
- The instance variable objects of C.
(Objects created by M, or by functions or methods which M calls, and objects in global variables are considered as arguments of M.)
And this all makes sense to me. Except for one part (paraphrasing to simplify):
Objects CREATED by methods which M calls are considered as arguments of M (adheres to 1st rule)
The paper also says this:
The Law prohibits the nesting of generic accessor function calls, which return objects that are not instance variable objects.
It allows the nesting of constructor function calls.
An accessor function is a function which returns an object which did exist before the function is called. A constructor function returns an object which did not exist before the function is called.
so then, the example below is considered adhering to LoD, if each method returns a new instance of some kind of object ?
function text(BookClass book) {
book.pages().last().text()
}
but doesn't adhere to the law if those same methods return existing instances of objects / primitive values ? it doesn't matter what kind of object is returned, just as long as it's created in the called method ? so then where is the loose coupling, information hiding and the other benefits, if this adheres to the law of Demeter ?
I feel like i'm missing something here.
The Law of Demeter is written to be language-agnostic, which accounts for the generic definitions of "accessor" and "constructor".
A given (OO) language typically has specific syntax for creating new Objects. For example, in Java, a "constructor function" is always preceded by the
newkeyword. So the generic description,...allows M to make constructor calls using the
newkeyword in Java. Objects returned from these constructor calls, "are considered as arguments of M."Here is the Law of Demeter in Java code, following the order in which the rules are described in the aforementioned paper.
It would be easier to read the LoD if it was written separately for each language using only syntax specific to that language. But to describe a general principle the authors combined terminology. The term "constructor" means different things in different languages. To apply the principle to your language, you must substitute the syntax defined by your language. A commonality across languages is that a constructor "returns an object which did not exist before..." In addition, a constructor is defined by the syntax of your language. A method may call this syntax and nest/chain calls onto the new Object.
For example, my language is Java. In Java, the only syntax for a constructor looks like:
new Object(). This function call does two things.Now, having a new object isn't very useful to my method unless I call methods on that new object. So the LoD specifically "allows the nesting of constructor function calls" meaning I can chain something like:
new Object().toString()which would not be allowed ifnew Object()was a normal, non-constructor function.The phrase, "allows the nesting of constructor function calls" means any number of methods can be called on the new object returned from a constructor. Since these additional methods are not constructor function calls themselves, nesting calls onto them is not allowed. In other words, the following can all be called by M.
new Object().secondObject()new Object().thirdObject()new Object().fourthObject()But M cannot call
new Object().secondObject().thirdObject()becausesecondObject()is not a constructor function call (in my language) and therefore does not allow nesting/chaining. The LoD allows nesting on constructor function calls. It does not allow nesting on all function calls.