Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

The principle Tell Don't Ask says:

you should endeavor to tell objects what you want them to do; do not ask them questions about their state, make a decision, and then tell them what to do.

The problem is that, as the caller, you should not be making decisions based on the state of the called object that result in you then changing the state of the object. The logic you are implementing is probably the called object’s responsibility, not yours. For you to make decisions outside the object violates its encapsulation.

A simple example of "Tell, don't Ask" is

Widget w = ...;
if (w.getParent() != null) {
  Panel parent = w.getParent();
  parent.remove(w);
}

and the tell version is ...

Widget w = ...;
w.removeFromParent();

But what if I need to know the result from the removeFromParent method? My first reaction was just to change the removeFromParent to return a boolean denoting if the parent was removed or not.

But then I came across Command Query Separation Pattern which says NOT to do this.

It states that every method should either be a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer. More formally, methods should return a value only if they are referentially transparent and hence possess no side effects.

Are these two really at odds with each other and how do I choose between the two? Do I go with the Pragmatic Programmer or Bertrand Meyer on this?

share|improve this question
1  
what would you do with the boolean ? –  David Nov 8 '11 at 16:39
1  
It sounds like you're diving too far into coding patterns without balancing out usability –  Izkata Nov 8 '11 at 22:18
    
Re boolean ... this is an example that was easy to piggy back off but similar to the write operation down below, the goal is for it to be a status of the operation. –  Dakotah North Nov 9 '11 at 10:51
1  
my point is that you should not focus on "returning something" but more on what you want to do with it. As I said in another comment, if you focus on failure, then use exception, if you want to do something when the operation is complete, then use callback or events, if you want to log what happened it is Widget responsibility... That's why I'm asking for your needs. If you can't find a concrete example where you need to return something, maybe that means that you won't have to choose between the two. –  David Nov 9 '11 at 11:52

3 Answers 3

Actually your example problem already illustrates lack of decomposition.

Let's just change it a slight bit:

Book b = ...;
if (b.getShelf() != null) 
    b.getShelf().remove(b);

This is not really different, but makes the flaw more apparent: Why would the book know about its shelf? Simply put, it shouldn't. It introduces a dependency of books on shelves (which doesn't make sense) and creates circular references. It's all bad.

Likewise it is not necessary for a widget to know its parent. You will say: "Ok, but the widget needs it's parent to properly layout itself etc." and under the hood the widget knows its parent and asks it for its metrics to calculate its own metrics based on them etc. According to ask, don't tell this is wrong. The parent should tell all its children to render, passing all necessary information as arguments. This way one can easily have the same widget in two parents (whether or not this actually makes sense).

To come back to the book example - enter the librarian:

Librarian l = ...;
Book b = ...;
l.findShelf(b).remove(b);

Please understand, that we're not asking anymore in the sense of tell, don't ask.

In the first version, the shelf was a property of the book and you asked for it. In the second version, we make no such assumption about the book. All we know is that the librarian can tell us a shelf that contains the book. Presumably he relies on some kind of lookup table to do so, but we don't know for sure (he could also just loop through all books in every shelf) and actually we don't want to know.
We do not rely on whether or how the librarians response is coupled to its state or that of other objects it might depend on. We tell the librarian to find the shelf.
In the first scenario, we directly encoded the relationship between a book and a shelf as a part of the book's state and retrieved this state directly. This is very fragile, because we also make the assumption that the shelf given back by the book contains the book (this is a constraint that we must ensure, otherwise we might be unable to remove the book from the shelf it's actually in).

With the introduction of the librarian, we model this relationship separately, therefore achieving separation of concern.

share|improve this answer
    
I think this is a very valid point, but does not answer the question at all. In your version the question is, should the remove(Book b) method in the Shelf class have a return value? –  scarfridge Jul 7 '12 at 12:07
1  
@scarfridge: At the bottom line, tell, don't ask is a corollary of proper separation of concerns. If you think about it, I thus do answer the question. At least I would think so ;) –  back2dos Jul 7 '12 at 16:57
1  
@scarfridge Instead of a return value, one could pass a function/delegate that gets called on failure. If is succeeds, you're done, right? –  Bless Yahu Jul 18 '12 at 22:25
1  
@BlessYahu That seems over-engineered to me. I personally feel that Command-query separation is more of an ideal in the real (multi-threaded) world. IMHO it is okay for a method with side-effects to return a value as long as the name of the method clearly indicates, that it will change the object's state. Consider the pop() method of a stack. But a method with a query name should not have side-effects. –  scarfridge Jul 19 '12 at 8:07

If you need to know the result, then you do; that's your requirement.

The phrase "methods should return a value only if they are referentially transparent and hence possess no side effects" is a good guideline to follow (especially if you're writing your program in a functional style, for concurrency or other reasons), but it's not an absolute.

For example, you may need to know the result of a file write operation (true or false). That's an example of a method that returns a value, but always produces side effects; there's no way around that.

To fulfill Command/Query Separation, you would have to perform the file operation with one method, and then check its result with another method, an undesirable technique because it decouples the result from the method that caused the result. What if something happens to the state of your object between the file call and the status check?

The bottom line is this: if you are using the result of a method call to make decisions elsewhere in the program, then you are not violating Tell Don't Ask. If, on the other hand, you're making decisions for an object based on a method call to that object, then you should move those decisions into the object itself to preserve encapsulation.

This is not at all contradictory with Command Query Separation; in fact, it further enforces it, because there's no longer a need to expose an external method for status purposes.

share|improve this answer
    
One could argue that in your example, if the "write" operation fails, an exception should be thrown, so there's no need for a "get status" method. –  David Nov 8 '11 at 16:21
    
@David: Then fall back on the OP's example, which would return true if a change actually occurred, false if it didn't. I doubt you'd want to throw an exception there. –  Robert Harvey Nov 8 '11 at 16:22
    
Even the OP's example does not feel right for me. Either you do want to be noticed if removal was not possible, in which case you would use exception or you want to be noticed when a widget is actually removed in which case you could use event or callback mechanism. I just don't see a real example where you would not want to respect " Command Query Separation Pattern" –  David Nov 8 '11 at 16:29
    
@David: I have edited my answer to clarify. –  Robert Harvey Nov 8 '11 at 16:30
    
Not to put too fine a point on it, but the whole idea behind command-query separation is that whoever issues the command to write the file doesn't care about the result - at least, not in a specific sense (a user might later pull up a list of all recent file operations, but that has no correlation to the initial command). If you need to take actions after a command completes, regardless of whether or not you care about the result, the correct way to do that is with an asynchronous programming model using events which (might) contain details about the original command and/or its result. –  Aaronaught Nov 8 '11 at 16:59

I think that you should go with your initial instinct. Sometimes the design should be intentionally dangerous, to introduce complexity immediately when you communicate with the object so that your forced handle it properly straight away, instead of trying to handle it on the object itself and hide all the gory details and make it hard to cleanly change the underlying assumptions.

You should get a sinking feeling if an object offers you implemented equivalents of open and close behaviors and you immediately begin to understand what your dealing with when you see a boolean return value for something you thought would be a simple atomic task.

How you deal with later on is your thing. You can create an abstraction above it, a widget type with removeFromParent(), but you should always have a low-level fallback, otherwise your were possibly making premature assumptions.

Don't try to make everything simple. There's nothing as disappointing when your rely on something that appears to be elegant and so innocent, only to realize it's true horror later on in the worst of moments.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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