Re: [Python-ideas] The prohibition overrides the class method

Thank you for the constructive responses, perhaps, I agree with you that this is not in the spirit of Python. As for the real example of the use, sometimes there to make the implementation of the method in the base class, but that none of the rest of the development team could not accidentally or unknowingly override this method (perhaps due to the need to be unsuccessful architecture).

You could always put this in the docstring: DO NOT OVERRIDE THIS METHOD. IF YOU OVERRIDE THIS METHOD, YOU WILL DIE. Short, the-the-point, and evokes fear. ... Seriously, though, I personally think this might go well with the whole PEP 484 type-annotation thing. I mean, if there are already generics and abstract methods. If we're going for static typing, adding final would fit well. Something like: @finalmethod def whatever(self): ... The type checker (in this case, Mypy) would check it, but there would be no runtime effect. On November 16, 2015 12:15:55 PM CST, "Иван Спиненко" <spinenkoia@gmail.com> wrote:
-- Sent from my Nexus 5 with K-9 Mail. Please excuse my brevity.

On Nov 16, 2015, at 10:24, Ryan Gonzalez <rymg19@gmail.com> wrote:
Sure, until the first time someone accidentally violates it and doesn't die. Then you will have trained him to ignore your docstrings, comments, type annotations, and warnings completely. (Of course you could take the OP's code and add some stuff that causes the hard drive casing and spindle to break, firing the platter at the developer's skull like one of those discs from the Dolph Lundgren movie I Come in Peace, but that would break compatibility with computers that only have SSDs, and I don't think that's feasible in 2015.)
Yes, that makes sense. If the feature isn't supposed to have any runtime effect, and is modeled after something that's definitely compile-time-centric in C++ and friends, signaling that by importing it from typing seems to be a pretty clear way to get that across. Although I still don't know why we need it. See below:
If it's just part of the implementation of the base class, just double-underscore it so that it can't be accidentally overridden (or called). It's only when something is also part of the interface that this is a problem. And it's kind of strange to have something be part of the interface of a type, but not be refinable by subtypes. When would you want that? (And as for accidental overriding, if a class claims doesn't even know what the interface of some supertype is, it probably shouldn't be inheriting—either it should be a mixin for someone who does know the supertype to compose, or it should be encapsulating rather than inheriting.) Do you have a concrete example of some code where you wanted finalmethod, and would use it to prevent the rest of your team from overriding it?

On Mon, Nov 16, 2015 at 3:59 PM, Andrew Barnert <abarnert@yahoo.com> wrote:
Well, it's just as easy to ignore type annotations and call `int(None)`. (You should definitely patent that hard drive stuff, though! ;)
What about http://programmers.stackexchange.com/a/288974/118754? -- Ryan [ERROR]: Your autotools build scripts are 200 lines longer than your program. Something’s wrong. http://kirbyfan64.github.io/

For that envelopes example on StackExchange, I'd probably use name mangling to reduce chances of subclassing mistakes and have prepare() call stuff(), seal(), stamp() in the correct order or whatever those were. I'm not sold in the need for "final". Btw, why does my iPad not have a back tick on the keyboard? My Android can do it... On Mon, Nov 16, 2015 at 5:53 PM Ryan Gonzalez <rymg19@gmail.com> wrote:

On Mon, Nov 16, 2015 at 5:15 PM, Michael Selik <mike@selik.org> wrote:
Maybe the subclasses should be able to access the functions. They just shouldn't override it.
Btw, why does my iPad not have a back tick on the keyboard? My Android can do it...
Android > iPad. *ducks from incoming bullets*
-- Ryan [ERROR]: Your autotools build scripts are 200 lines longer than your program. Something’s wrong. http://kirbyfan64.github.io/

On Nov 16, 2015 4:15 PM, "Michael Selik" <mike@selik.org> wrote:
For that envelopes example on StackExchange, I'd probably use name
mangling to reduce chances of subclassing mistakes and have prepare() call stuff(), seal(), stamp() in the correct order or whatever those were. I'm not sold in the need for "final". Name mangling would not work in that example. The prepare method is defined by a base class and overridden in a subclass; it is the subclass that wishes to declare the method final. Name mangling would obstruct overriding the method at all, which would be a problem for the base class that invites the method to be overridden.

Thanks, Ian, I missed that detail. While my initial thought was that name mangling would achieve the desired level of subclassing-clumsiness defense. As below... # using 2 steps instead of 3, for brevity class Envelope: def prepare(self): print('omnibus!') class Child(Envelope): def stuff(self): print('step 1') __stuff = stuff def seal(self): print('step 2') __seal = seal def prepare(self): self.__stuff() self.__seal() The post on StackExchange added the extra wrinkle that both classes have C++ virtual functions, kind-of like this... from abc import ABC, abstractmethod class Envelope(ABC): def something_useful(self): ''' I'd normally avoid tricky inheritance but there must be some really useful code in here that I don't want to refactor ''' @abstractmethod def prepare(self): pass class Child(Envelope): @abstractmethod def stuff(self): print('step 1') @abstractmethod def seal(self): print('step 2') def prepare(self): 'should be FINAL, Override at your OWN PERIL' self.stuff() self.seal() This contrived scenario seems better resolved by refactoring the `Envelope` class. Moreover, I don't understand why the `Child` class would exist at all. Why override `prepare` only to create more abstract methods? On Mon, Nov 16, 2015 at 6:40 PM Ian Kelly <ian.g.kelly@gmail.com> wrote:

On Nov 16, 2015, at 16:12, Michael Selik <mike@selik.org> wrote:
Apparently, because they want to use the strategy pattern, twice, but in a way that gets none of the advantages of that pattern. To actually get the benefits, those new abstract methods would not be in Child; instead, you'd create a new EnvelopePrepaper interface that Child uses. Why can't you just merge the EnvelopePreparer into Child itself? Because then you lose all the decoupling benefits that the strategy pattern is meant to provide, and you add new problems in that a single class now has multiple separate interfaces that can accidentally step on each other's toes. In fact, what they clearly wanted was for Envelope to use a preparer strategy, and for Child to _be_ such a preparer strategy that itself uses a 2-stage-preparer strategy, and for other people to implement 2-stage-preparer strategies. But then they've merged both interfaces into the class that uses those strategies instead for no good reason. If you fix either of those problems, or just use a simpler design instead of misusing strategy, or even if you only misuse strategy once instead of multiple times, the problem wouldn't arise. In other words, it's a subset of exactly the problem I suggested before seeing the example: If you want to inherit from a class, you have to know that class's interface, because you're promising to implement it. This design forces users to inherit from a class whose interface they don't know, and then hopes for a new language feature to hide one of the symptoms of that problem instead of fixing the problem.

You could always put this in the docstring: DO NOT OVERRIDE THIS METHOD. IF YOU OVERRIDE THIS METHOD, YOU WILL DIE. Short, the-the-point, and evokes fear. ... Seriously, though, I personally think this might go well with the whole PEP 484 type-annotation thing. I mean, if there are already generics and abstract methods. If we're going for static typing, adding final would fit well. Something like: @finalmethod def whatever(self): ... The type checker (in this case, Mypy) would check it, but there would be no runtime effect. On November 16, 2015 12:15:55 PM CST, "Иван Спиненко" <spinenkoia@gmail.com> wrote:
-- Sent from my Nexus 5 with K-9 Mail. Please excuse my brevity.

On Nov 16, 2015, at 10:24, Ryan Gonzalez <rymg19@gmail.com> wrote:
Sure, until the first time someone accidentally violates it and doesn't die. Then you will have trained him to ignore your docstrings, comments, type annotations, and warnings completely. (Of course you could take the OP's code and add some stuff that causes the hard drive casing and spindle to break, firing the platter at the developer's skull like one of those discs from the Dolph Lundgren movie I Come in Peace, but that would break compatibility with computers that only have SSDs, and I don't think that's feasible in 2015.)
Yes, that makes sense. If the feature isn't supposed to have any runtime effect, and is modeled after something that's definitely compile-time-centric in C++ and friends, signaling that by importing it from typing seems to be a pretty clear way to get that across. Although I still don't know why we need it. See below:
If it's just part of the implementation of the base class, just double-underscore it so that it can't be accidentally overridden (or called). It's only when something is also part of the interface that this is a problem. And it's kind of strange to have something be part of the interface of a type, but not be refinable by subtypes. When would you want that? (And as for accidental overriding, if a class claims doesn't even know what the interface of some supertype is, it probably shouldn't be inheriting—either it should be a mixin for someone who does know the supertype to compose, or it should be encapsulating rather than inheriting.) Do you have a concrete example of some code where you wanted finalmethod, and would use it to prevent the rest of your team from overriding it?

On Mon, Nov 16, 2015 at 3:59 PM, Andrew Barnert <abarnert@yahoo.com> wrote:
Well, it's just as easy to ignore type annotations and call `int(None)`. (You should definitely patent that hard drive stuff, though! ;)
What about http://programmers.stackexchange.com/a/288974/118754? -- Ryan [ERROR]: Your autotools build scripts are 200 lines longer than your program. Something’s wrong. http://kirbyfan64.github.io/

For that envelopes example on StackExchange, I'd probably use name mangling to reduce chances of subclassing mistakes and have prepare() call stuff(), seal(), stamp() in the correct order or whatever those were. I'm not sold in the need for "final". Btw, why does my iPad not have a back tick on the keyboard? My Android can do it... On Mon, Nov 16, 2015 at 5:53 PM Ryan Gonzalez <rymg19@gmail.com> wrote:

On Mon, Nov 16, 2015 at 5:15 PM, Michael Selik <mike@selik.org> wrote:
Maybe the subclasses should be able to access the functions. They just shouldn't override it.
Btw, why does my iPad not have a back tick on the keyboard? My Android can do it...
Android > iPad. *ducks from incoming bullets*
-- Ryan [ERROR]: Your autotools build scripts are 200 lines longer than your program. Something’s wrong. http://kirbyfan64.github.io/

On Nov 16, 2015 4:15 PM, "Michael Selik" <mike@selik.org> wrote:
For that envelopes example on StackExchange, I'd probably use name
mangling to reduce chances of subclassing mistakes and have prepare() call stuff(), seal(), stamp() in the correct order or whatever those were. I'm not sold in the need for "final". Name mangling would not work in that example. The prepare method is defined by a base class and overridden in a subclass; it is the subclass that wishes to declare the method final. Name mangling would obstruct overriding the method at all, which would be a problem for the base class that invites the method to be overridden.

Thanks, Ian, I missed that detail. While my initial thought was that name mangling would achieve the desired level of subclassing-clumsiness defense. As below... # using 2 steps instead of 3, for brevity class Envelope: def prepare(self): print('omnibus!') class Child(Envelope): def stuff(self): print('step 1') __stuff = stuff def seal(self): print('step 2') __seal = seal def prepare(self): self.__stuff() self.__seal() The post on StackExchange added the extra wrinkle that both classes have C++ virtual functions, kind-of like this... from abc import ABC, abstractmethod class Envelope(ABC): def something_useful(self): ''' I'd normally avoid tricky inheritance but there must be some really useful code in here that I don't want to refactor ''' @abstractmethod def prepare(self): pass class Child(Envelope): @abstractmethod def stuff(self): print('step 1') @abstractmethod def seal(self): print('step 2') def prepare(self): 'should be FINAL, Override at your OWN PERIL' self.stuff() self.seal() This contrived scenario seems better resolved by refactoring the `Envelope` class. Moreover, I don't understand why the `Child` class would exist at all. Why override `prepare` only to create more abstract methods? On Mon, Nov 16, 2015 at 6:40 PM Ian Kelly <ian.g.kelly@gmail.com> wrote:

On Nov 16, 2015, at 16:12, Michael Selik <mike@selik.org> wrote:
Apparently, because they want to use the strategy pattern, twice, but in a way that gets none of the advantages of that pattern. To actually get the benefits, those new abstract methods would not be in Child; instead, you'd create a new EnvelopePrepaper interface that Child uses. Why can't you just merge the EnvelopePreparer into Child itself? Because then you lose all the decoupling benefits that the strategy pattern is meant to provide, and you add new problems in that a single class now has multiple separate interfaces that can accidentally step on each other's toes. In fact, what they clearly wanted was for Envelope to use a preparer strategy, and for Child to _be_ such a preparer strategy that itself uses a 2-stage-preparer strategy, and for other people to implement 2-stage-preparer strategies. But then they've merged both interfaces into the class that uses those strategies instead for no good reason. If you fix either of those problems, or just use a simpler design instead of misusing strategy, or even if you only misuse strategy once instead of multiple times, the problem wouldn't arise. In other words, it's a subset of exactly the problem I suggested before seeing the example: If you want to inherit from a class, you have to know that class's interface, because you're promising to implement it. This design forces users to inherit from a class whose interface they don't know, and then hopes for a new language feature to hide one of the symptoms of that problem instead of fixing the problem.
participants (7)
-
Andrew Barnert
-
Greg Ewing
-
Ian Kelly
-
Joseph Jevnik
-
Michael Selik
-
Ryan Gonzalez
-
Иван Спиненко