Tell, don't ask

This principle is another way of expressing polymorphism in OOP.

Imagine a piece of code where you test (with an if statement) if a variable has a value. This is called “asking”, because you're asking whether a condition holds.

Tell, don't ask, wants you to remove the if, and instead tell the code what it should do. How do you accomplish this? With polymorphism!

You could create instead a new type (interface), and multiple implementations of that interface, each of the implementation holding the body of the if statement.

Then, because of inversion of control, you would inject the correct behavior from outside.

Example violating this principle

Imagine we want to connect via FTP. By design, the protocol allows two modes: active and passive.

Let's look at a naïve implementation.

class FTPConnection {
    public FTPConnection(credentials, mode) {
        this.connect(credentials);
        if (mode == 'passive') {
            this.set_passive(true);
        }
    }
}
 
ftp = new FTPConnection(credentials, 'passive');

Refactoring the example w.r.t. tell, don't ask

The if is the “ask” part. Instead, we should create a new type and two implementations: Active and Passive

class FTPConnection {
    public FTPConnection(credentials, Mode mode) {
        this.connect(credentials);
        mode.onConnect(this);
    }
}

interface Mode {
    public onConnect(ftp);
}

class Passive implements Mode {
        public onConnect(ftp) {
            ftp.set_passive(true);
        }
}

class Active implements Mode {
        public onConnect(ftp) {
        }
}

ftp = new FTPConnection(credentials, new Passive());

In the refactored example, multiple principles and design patterns come into play:

  • tell, don't ask: in the last line, the if got replaced by a new object (new Passive)
  • null object: the class Active is an example of a null object
  • inversion of control: we construct the mode outside of the class (the last line in the example)
  • program to an interface: Mode is an interface
  • Polymorphism objects of type Active and Passive have two types (thus polymorphic): Mode and the type itself
  • reduce_the_number_of_ifs Because there is no more if