13

I have three questions concerning Demeter's law.

Apart from classes which were specifically appointed to return objects - such as factory and builder classes - is it okay for a method to return an object, e.g. an object held by one of the class's properties or would that violate the law of demeter (1)? And if it violates the law of demeter, would it matter if the object returned is an immutable object that represents a piece of data and contains nothing but getters for this data (2a)? Or is such a ValueObject an anti-pattern in itself, because everything that is done with the data in that class is done outside of the class (2b)?

In pseudo code:

class A {}

class B {

    private A a;

    public A getA() {
        return this.a;
    }
}

class C {

    private B b;
    private X x;

    public void main() {
        // Is it okay for B.getA to exist?
        A a = this.b.getA();

        a.doSomething();

        x.doSomethingElse(a);
    }
}

I suspect that Demeter's law forbids a pattern such as the above. What can I do to ensure that doSomethingElse() can be called while not violating the law (3)?

  • 9
    A lot of people (functional programmers in particular) view the Law of Demeter as an anti-pattern. Others view it as the "Occasionally Useful Suggestion of Demeter." – David Hammen Jun 18 '16 at 14:36
  • 1
    I'm going to upvote this question cause it illustrates the absurdities the Law of Demeter. Yes, LoD is "occasionally useful", but its usually stupid. – user949300 Jun 18 '16 at 17:13
  • How is x getting set? – candied_orange Jun 18 '16 at 18:59
  • @CandiedOrange x is just a different property whose value is just some object that is able to invoke doSomethingElse. – user2180613 Jun 18 '16 at 19:09
  • 1
    Your example doesn't violate LOD. LOD is about preventing clients of an object from coupling to that objects internal details or collaborators. you want to avoid things like user.currentSession.isLoggedIn(). because it couples clients of user to not only user but also its collaborator, session. Instead you want to be able to write user.isLoggedIn(). this is usually achieved by adding an isLoggedIn method to user whose implementation delegates to currentSession. – Jonah Jun 23 '16 at 3:19
7

In many programming languages, all returned values are objects. As others have said, not being able to use the methods of returned objects forces you to never return anything at all. You should be asking your self, "What are the responsibilities of class A, B and C?" This is why using metasyntactic variable names like A, B and C always solicit the answer "it depends" because there is no inherit responsibilities in those terms.

You may want to look into Domain Driven Design, which will give you a more nuanced set of heuristics to reason about where functionality should go and who should be invoking what.

Your second question concerning immutable objects speaks to the notion of a
Value Object compared to an Entity object. in DDD, You can pass value objects around with almost no restrictions. This does not speak true for entity objects.

The simplistic LOD is much better expressed in DDD as the rules for accessing Aggregates. No external objects should hold references to members of aggregates. Only a root reference should be held.

DDD aside, you at least want to develop your own sets of stereotypes for your classes that are reasonable for your domain. Enforce rules about those stereotypes as you design your system.

Also always remember that all of these rules are to manage complexity, not to hamstring yourself.

  • 1
    Does DDD provide any rules as to when class members such as data can be exposed (i.e. getters should exist)? All discussions around Law of Demeter, tell, don't ask, getters are evil, object encapsulation and single responsibility principle seem to boil down to this question: when should delegation to a domain object be used as opposed to getting the object's value and doing something with it? It would be very useful to be able to apply nuanced qualifications to situations where such a decision must be made. – user2180613 Jun 20 '16 at 9:45
  • Guidelines like "getters are evil" exist because many people treat class instances as data structures (A bag of data to be passed around). This is not object-oriented programming. Objects are bundles of functionality/behavior that actually provide some work. The scope of work is defined by the responsibility. This work is going to obviously create objects that get returned from methods, etc. If your class is actually doing meaningful work that you can clearly define beyond "represent data object X with attributes Y and Z", then you're on the right path. I wouldn't stress over it. – Jeremy Jun 20 '16 at 16:58
  • To expand on that point, when you use a lot of getters/askers, that usually means you have some large method somewhere that is orchestrating everything, which Fowler calls a transaction script. Before you start to use a getter, ask yourself...why am I asking for this data from the object? Why isn't this functionality in a method on the object? If It's not the responsibility of this class to implement this functionality, then go ahead and use a getter. The book [Refactoring] (martinfowler.com/books/refactoring.html) by Fowler is a book on heuristics for such questions. – Jeremy Jun 20 '16 at 17:07
  • In his book Implementing Domain-Driven Design, Vaughn Vernon has a mention of the Law of Demeter and Tell, Don't Ask in Ch 10, pp 382. Might be worth a look if you have access to it. – Jeremy Jun 24 '16 at 1:31
5

According to Demeter's law, is a class allowed to return one of its members?

Yes it most certainly is.

Let's look at the main points:

  • Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.
  • Each unit should only talk to its friends; don't talk to strangers.
  • Only talk to your immediate friends.

All three of which leave you asking one question: Who is a friend?

When deciding what to return, The Law of Demeter or principle of least knowledge (LoD) does not dictate that you defend against coders that insist on violating it. It dictates that you do not force coders to violate it.

Getting these confused is exactly why so many think a setter must always return void. No. You must allow a way to make queries (getters) that do not change the state of the system. That's basic command query separation.

Does this mean you're free to delve into a code base chaining together whatever you want? No. Chain together only what was meant to be chained together. Otherwise the chain might change and suddenly your stuff is broken. This is what is meant by friends.

Long chains can be designed for. Fluent interfaces, iDSL, much of Java8, and good old StringBuilder are all meant to let you build long chains. They don't violate LoD because everything in the chain is meant to work together and promised to keep working together. You violate demeter when you chain together stuff that never heard of each other. Friends are those that promised to keep your chain working. Friends of Friends did not.

Apart from classes which were specifically appointed to return objects - such as factory and builder classes - is it okay for a method to return an object, e.g. an object held by one of the class's properties or would that violate the law of demeter (1)?

This only creates an opportunity to violate demeter. This is not a violation. This is not even necessarily bad.

And if it violates the law of demeter, would it matter if the object returned is an immutable object that represents a piece of data and contains nothing but getters for this data (2)?

Immutable is good but irrelevant here. Getting at stuff through a longer chain doesn't make it better. What makes it better is separating the getting from the using. If you're using, ask for what you need as a parameter. Don't go hunting for it by delving into the getters of strangers.

In pseudo code:

I suspect that Demeter's law forbids a pattern such as the above. What can I do to ensure that doSomethingElse() can be called while not violating the law (3)?

Before I talk about x.doSomethingElse(a) understand that you've basicly written

b.getA().doSomething()

Now, LoD is not a dot counting exercise. But when you create a chain you're saying that you know how to get an A (by using B) and you know how to use an A. Well now A and B had better be close friends because you just coupled them together.

If you had just asked for something to hand you an A like thing you could use A and wouldn't have cared where it came from and B could live a life happy and free of your obsession with getting A from B.

As for x.doSomethingElse(a) without details of where x came from, LoD has nothing at all to say about it.

LoD can encourage separating use from construction. But I will point out if you religiously treat every object as not friendly you'll be stuck writing code in static methods. You can build a wonderfully complex object graph in main this way but eventually you have to call a method on it to start the thing working. You simply have to decide who your friends are. There's no getting away from that.

So yes, a class is allowed to return one of its members under LoD. When you do you should make clear if that member is friendly with your class because if it's not, some client may try coupling you to that class by using you to get it before using it. That's important because now what you return must always support that use.

There are many cases where this is simply not a concern. Collections can ignore this simply because they are meant to be friends with everything that uses them. Similarly value objects are friendly with everyone. But if you wrote an address validating utility that demanded an employee object that it extracted an address from, rather then just ask for the address, well you'd better hope that the employee and address both came from the same library.

  • Fluent interfaces aren't an exception to LOD because of some notion of friendliness.... In a fluent interface, each of the methods in the chain are called on the same object, because they all return self. settings.darkTheme().monospaceFont() is just syntactic sugar for settings.darkTheme(); settings.monospaceFont(); – Jonah Jun 23 '16 at 3:25
  • 3
    @Jonah Returning self is the ultimate friendliness. And not all fluent interfaces do. Many iDSL's are also fluent and return differing types to change the available methods at different points. Consider jOOQ, step builder, wizard builder, and my own nightmarish monster builder. Fluent is a style. Not a pattern. – candied_orange Jun 23 '16 at 3:47
2

Apart from classes which were specifically appointed to return objects [...]

I don't quite understand this argument. Any object can return an object as a result of a message invokation. Especially if you think in "everything as object".

Classes however, are the only objects that can instantiate new objects of their own kind by sending them the "new" message (or often replaced with a new keyword on most common OOP languages)


Anyway, regarding your question I'd be rather suspicious about an object returning one of its properties in order to be used elsewhere. It could be that this object would be leaking out information about either its state or its implementation details.

And you wouldn't want the C object to know about implementation details of B. This is an unwanted dependency on the A object from the C object perspective.

So you may want to ask yourself if C, by knowing A, is not knowing too much for the work he has to do, independently of the LOD.

There are cases where this can be legitimate, for example, asking a collection object for one of its items is appropriate and not breaking any Demeter rule. Asking a Book object for its SQLConnection object on the other hand, is risky and should be avoided.

The LOD exists because many programmers tend to ask objects for information before performing a work out of it. LOD is there to remind us that sometimes (if not always) we're just over-complicating things by wanting our objects to do too much. Sometimes we just have to ask another object to do the work for us. LOD is there to makes us think twice about where we place the behaviour in our objects.

0

Apart from classes which were specifically appointed to return objects - such as factory and builder classes - is it okay for a method to return an object?

Why wouldn't it be? You seem to suggest that it's necessary to signal to your fellow programmers that the class is specifically meant to return objects, or it must not return objects at all. In languages where everything is an object, this would severely limit your options, as you wouldn't be able to return anything at all.

  • The example is about the implicit b.getA().doSomething() and x.doSomethingElse(b.getA()) – user2180613 Jun 18 '16 at 14:53
  • A a = b.getA(); a.DoSomething(); -- back to one dot. – Robert Harvey Jun 18 '16 at 14:55
  • 2
    @user2180613 -- If you wanted to ask about b.getA().doSomething() and x.doSomethingElse(b.getA()) you should have explicitly asked about that. As it stands, your question appears to be about this.b.getA(). – David Hammen Jun 18 '16 at 15:02
  • 1
    As A is not a member of C, not created in C and not provided to C, it seems that using A in C (in whatever manner) violates LoD. Counting dots is not what LoD is about, it is only an illustrative tool. It is possible to convert Driver().getCar().getSteeringWheel().getFrontWheels().toRight() into separate statements that each contain one dot, but the violation of LoD is still there. I read in many posts on this forum that performing actions should be delegated to the object that implements the actual behaviour i.e. tell don't ask. Returning values seems to conflict with that. – user2180613 Jun 18 '16 at 15:27
  • 1
    I suppose that is true but it does not answer the question. – user2180613 Jun 18 '16 at 16:36
0

Depends on what you are doing. If you expose a member of your class, when it's nobody's business that this is a member of your class, or what the type of that member is, that's a bad thing. If you then change the type of that member, and the type of the function returning the member, and everyone has to change their code, that is evil.

On the other hand, if the interface of your class states that it will supply an instance of a well-known class A, that's fine. If you are lucky and you can do this by supplying a member of your class, good on you. If you changed that member from being an A to being a B, you would then need to rewrite the method that returns an A, obviously it will now have to construct one and fill it with available data, instead of just a one-liner returning a member. The interface of your class would be unchanged.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.