2

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.

16
  • 5
    "The getName method should obviously be final" Why? Also I don't think "final" is an OOP concept. Jul 22, 2017 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, 2017 at 19:41
  • 3
    @Sina "subclass should not change the name of the Dog!" How do you know? Maybe in my MrDog subclass Fido is named Mr.Fido. Jul 23, 2017 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, 2017 at 9:06
  • 3
    @sina the best plan for the future is the one that makes the fewest assumptions about the future. Jul 23, 2017 at 10:21

4 Answers 4

15

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.

8
  • 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, 2017 at 4:51
  • 1
    @TimothyTruckle: I don't understand your question. If you're referring to unit testing frameworks that require inheriting or overriding the classes/methods under test, I don't use those. If you need to substitute implementations for testing purposes (i.e. mocks), use interfaces. Personally I think the whole point of TDD is to encourage you to write code in such a way that you don't need elaborate testing techniques. Jul 23, 2017 at 16:52
  • 1
    @RobertHarvey "If you're referring to unit testing frameworks that require inheriting or overriding the classes/methods under test, I don't use those." I'm referring to mocking dependencied and the fact that almost each unit is a dependency to another unit. If your classes are final by default you cannot use mocks (neither own coded nor generated by frameworks) and therefore you cannot test your unit in isolation. Or are you implying that you provide interfaces for the "entry classes" to units? Jul 23, 2017 at 17:33
  • 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) Jul 23, 2017 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. Jul 23, 2017 at 20:16
0

In today's world where shift left quality tools are available, I generally do not think about whether to make a method final or not instead I would use a tool like PMD and define rules for static analysis to ensure

  1. A method parameter that is never re-assigned within the method should be declared final
  2. A class with only private constructors should be final unless the private constructor is invoked by an inner class.
  3. A local variable assigned only once should be declared final

Having such shift left checks using Static analysis tools will help you reduce the stress you can just stop thinking about where to use the final and just think about solving the problem at hand and the design of your system.

I landed at this question some days back to figure out answers for similar questions. After solving my problem, I created a blog post explaining how you can enforce your to make best use of final modifier

The Java Final Modifier, What is the right way to use it ?, How do I enforce the right way?

0

Note: It's been years since I did PHP, please forgive minor syntax mistakes.

It seems you're misunderstand what final does and why it should be used.

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

The final keyword doesn't prevent this->name from being changed. As evidence by the following example:

class Dog
{
    private $name;

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

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

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

What final does is prevent inheritance overriding. Normally, derived classes can override the implementation of a base class' method, e.g.:

class NobleDog extends Dog 
{
   public function getName() 
   {
       return "Sir " . $this->name;
   }
}

If you assume my implementation of Dog and NobleDog, you can see that you can always change a dog's name, but even when you change their name to e.g. "NEWNAME", a noble dog will still be called "Sir NEWNAME", whereas a normal dog will just be called "NEWNAME".

By making getName() final in the base class, the NobleDog derived class cannot override this anymore, and it therefore cannot e.g. prepend "Sir" to a dog's getName() result.


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

The problem here is that you register the dog with a specific name, and if that dog's name changes afterwards (for whatever reason), the registration in registredDogs itself is not updated and still uses the old name.

Because this->name is made reasonably immutable in your Dog class, that is currently not an issue. However, it's always possible that someone later decides to add a method to Dog that does change its name.

Whether you consider that a real issue you need to actively protect against is up to you. I tend to expect developers to understand that this name shouldn't be changed since there's no setter in the class and it's made private, but your mileage (and developer team) may vary.

Sadly, there is no real "readonly" property in PHP, which would prevent any issues with this name unexpectedly changing.

If your main concern is being able to query registredDogs with the current name of the dog, regardless of whether it has been changed or not, then you shouldn't set its key based on the dog's name, but instead you have to dynamically query your collection and find the matching name. This ensure that the current name is the one you're matching against.

Something like:

public function getDog($name)
{
    $found= null;
    foreach($registredDogs as $dog) 
    {
        if ($name == $dog->getName()) 
        {
            $found = $dog;
            break;
        }
    }
    return $found;
}

This is of course less performant than an index-based lookup, but it does allow for changed values to be accounted for.

Please excuse any syntax errors I may have made, it's been a while since I did PHP.


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

Just because someone can override a method doesn't mean that literally any valid code they write is therefore a correct implementation.

Selecting one element instead of many feels like an incorrect implementation, but e.g. selecting many elements and then doing some additional filtering on that array sounds perfectly fine.

Developers writing incorrect (but syntactically valid) code is not something you can prevent. If it were, then we would've either solved P=NP or we wouldn't never need to test/debug ever again.

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?

First of all, for this specific issue, assume that developers will write a correct implementation when overriding your method. The correctness of what they do isn't relevant here.

What is relevant, is whether you want developers to be able to change your method implementation in a derived class. Sometimes you want that, sometimes you don't. That's very contextual.

If you're making a base class which is intended to have some reusable component that is forced to be consistent between derivations of this base class, then you're likely going to want to be using final.

This is slightly language specific. PHP makes everything overridable by default and requires you to explicitly prevent overriding. C#, by comparison, makes everything "final" by default and requires you to explicitly make a method virtual to enable overriding.

I'm a C# dev, so I'm naturally a fan of opt-in overriding, i.e. nothing can be overridden except when explicitly made to be. But PHP devs are liable to think the other way, because that's what they're used to.

I'd suggest sticking with whatever your language chose as the default behavior, simply because it means that you don't have to pepper your final/virtual keywords all across your codebase.

Edit: Robert Harvey makes a reasonable point that you might want to be more liberal with final when dealing with third parties using your code. It all depends on whether abusing it is actually harmful to you, or simply renders the third party's product defective. In the latter case, there's less reason for you to actively defend against this.

0

If this happens within a development team, where everyone has access to all the source code, using "final" doesn't mean others can't override the function. It means they can't override the function without removing the word "final" in the source code.

So you should always use "final" if you haven't designed your class for the consequences of overriding a function. Which is the default case. It's then up to the person who wants to override it to figure out why they need the override, and figure out what the consequences of that override are, and when that is all solved then the "final" can be removed. Or they figure out that it wasn't a good idea to override and solve their problem in a different way.

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.