3

When I want to make a method final, first of all I ask myself:

Should this method be final?

The answer is obvious sometimes, for example imagine this:

class Dog
{
    private $name;

    public function __constructor($name)
    {
        this->name = $name;
    }

    final public function getName()
    {
        return this->name;
    }
}

The getName method should obviously be final.

Some guys ask why this is obvious? See this example:

class DogsSchool
{
    private $registredDogs = [];

    final public function registerDog(Dog $dog)
    {
        this->registredDogs[$dog->getName()] = $dog;
    }
}

If people change the name of the dog in non-constructor methods for example in getName method, You can't register the dog in any collection like DogsSchool, You can't identify the dog cause the ID (here is the name) can be changed anytime. this will break your application. and also in the real world identifiers are final, Can you change your ID number after your birth? (birth = constructing in OO)

OK, no problem, BUT! I am getting confused sometimes! for example imagine this:

class SelectMany
{
    public function selectManyAndReturn()
    {
        return selectMany();
    }
}

Overwriting the selectManyAndReturn method can change the behavior of the class, people can overwrite it and run selectOne for example instead of selectMany, OK, I can make this method final also to prevent this, but by this way I am also preventing people form adding new features to the method, for example if I make the method final, I am not able to write a new child class like this one:

class SelectManyApple extends SelectMany
{
    public function selectManyAndReturn()
    {
        return selectManyApple();
    }
}

What should I do? Is forgetting final and private methods completely good idea? like many applications and many programming languages? or Can you tell me when exactly we should make a method final?

The question is language agnostic. It's about the general principle that I should use to write good OO programs.

  • 5
    "The getName method should obviously be final" Why? Also I don't think "final" is an OOP concept. – Stop harming Monica Jul 22 '17 at 19:28
  • 1
    I think the answer depends on the context. I don't fully understand the purpose of the SelectMany class and SelectManyApple subclass in the example, but this seems like it could be easy to violate LSP. Since SelectMany class doesn't specify what it is selecting it sounds like it'd be more of an abstract class (if using C#). – morbidhawk Jul 22 '17 at 19:41
  • 2
    @Sina "subclass should not change the name of the Dog!" How do you know? Maybe in my MrDog subclass Fido is named Mr.Fido. – candied_orange Jul 23 '17 at 1:57
  • 1
    My good rule of thumb is to make classes final until I can't. And when I can't I usually make a class abstract instead. – Andy Jul 23 '17 at 9:06
  • 2
    @sina the best plan for the future is the one that makes the fewest assumptions about the future. – candied_orange Jul 23 '17 at 10:21
12

If you're distributing code to the public, always make your classes and methods final, unless the class or method is specifically designed to be overridden or inherited.

When should you make a class or method final? When you don't want a user of your class (i.e. some entity with which you can't enforce policies) to override it. You make a class final when you don't want a user to inherit from it.

Naturally, this just raises the question "when might you not want a user to override or inherit?" In any non-trivial design, nearly always. In the .NET Framework, classes are sealed by default.

The reason for this is simple: if a user overrides or inherits, you have no idea how to predict what that user might do with your class or method, nor can you provide any assurances that their actions won't break your class, your method or some other part of the system.

To put it another way, unless you carefully control how your class is used, you can't provide reasonable guarantees that it is going to work in all cases. By making your classes and methods final, you get to control the final behavior of them, and can therefore make statements about the behavior of your classes/methods with a reasonable degree of certainty, without having to worry about someone changing the behavior of your class or method in ways that you didn't predict.

So the question becomes, when should I allow a user to override?

When you've designed the method and/or class so that it is overridable in a way that is consistent with the class's design.

Some methods are meant to be overridden. The ToString() method is almost always overridable in most modern OO languages because it's merely an output, typically display only, and for many objects returns a default result that's not especially meaningful anyway.

An exception that proves the rule is Linq methods. Linq methods are extension methods, a mechanism in C# that allows the developer to "spot weld" arbitrary methods onto a type. The reason this works without breaking things is because the extension method does not have access to the internals of the class it is so modifying, but only to its public members.

  • Well, I could override toString() to deliberately, or accidently, throw an Exception. :-). Should that be sealed? For the record, everytime I've encountered a final class (or method) it's been very annoying. – user949300 Jul 23 '17 at 4:51
  • @user949300 no, toString is mostly non-final, if you throw exception in it you will break the language rules, this is not our problem I think, in the real world toString can be different except the times it follows special rule, for example you have a Uri class and this Uri class follows an RFC for toString, this toString should be final. – Sina Jul 23 '17 at 8:09
  • "Naturally, this just raises the question "when might you not want a user to override or inherit?" In any non-trivial design, nearly always." So if I have such "non trivial" design I'd really like to have UnitTest to verify the behavior of my code. But how do I separate code under test when its dependencies are final? – Timothy Truckle Jul 23 '17 at 15:20
  • 1
    @RobertHarvey "If you or the members of your coding team are the ones writing the classes and inheriting from them, my answer does not apply." looks like you and me have different definition of nearly always... ;o) – Timothy Truckle Jul 23 '17 at 17:53
  • 1
    @TimothyTruckle: I've clarified the meaning of "user" in my answer. Sealing framework or library classes is about controlling them in the wild, not strangling your own team. But even in your own organization, you should seal classes and make methods final unless you intend them to be overridden. Doing so provides strong documentation for how the class or method should properly be used. The worst that can happen is you make the decision later to unseal one for a specific purpose, a decision made much easier if it is done in-house. – Robert Harvey Jul 23 '17 at 20:16

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.