Guido van Rossum wrote: > On 4/23/07, Phillip J. Eby <[EMAIL PROTECTED]> wrote: >> At 04:49 PM 4/23/2007 -0700, Guido van Rossum wrote: >>>> I suppose there is some value in requiring people to override @abstract >>>> methods to make a subclass instantiable, versus merely using the lack of an >>>> @abstract class decorator to indicate that a subclass is concrete. But I >>>> wonder if being able to have just one @abstract decorator (that always >>>> means "you can't call this by default") mightn't be worth giving up that >>>> tiny bit of extra type checking? >>> I prefer to follow the lead of C++ here -- an abstract class is >>> abstract by virtue of having at least one abstract method. >> It's been way too long since I did any C++, but isn't it the case that an >> abstract (aka "pure virtual"?) method in C++ is one that *can't be >> invoked*? [pause to Google it...] Well I'll be darned. I didn't know you >> could actually provide an implementation for a pure virtual >> function. Hm. Learn something new every day... except while I was >> writing C++ evidently. :)
I'm not sure what Phillip is talking about here - C++ does not allow you to instantiate a class that has non-overridden pure virtual methods, and no pure virtual method can have a body. You cannot provide an implementation for a pure virtual function. Now, there are occasions in C++ where it is possible for buggy code to "call" a pure virtual function - but the result is always an exception. Recall that in C++, when an instance is destructed, as each base class's destructor is called the vtable pointer is modified to point to the vtable for that base class, not the vtable for the actual class of the instance. (I've always had problems with this rule, but there it is.) If you attempt to call a subclass method after that subclass's destructor has been called (which is, of course, an error), you may end up invoking the little stub function which a pure virtual vtable entry points to. This is about as "legal" as dereferencing memory after it has been freed. > Actually I just meant to follow its lead in defining that a class is > abstract as soon as one or more of its methods are abstract. In Java > you need to repeat this by making the class abstract; that seems > unpythonic. > >> But are there any other languages besides C++ that have this idiom? I'm >> not familiar with any that do (at least, not that I know of!), and the fact >> that C++ allows it seems a bit non-obvious to me. Java and C# pretty much >> do @abstract the way I proposed it, for example: >> >> Java: http://java.sun.com/docs/books/tutorial/java/IandI/abstract.html >> C#: http://www.codeproject.com/useritems/Abstract_CLS_MTHD.asp >> >> That is, they both separate class-abstraction from method-abstraction, even >> though the latter implies the former. Thus, you can have an abstract class >> 'Iterator' even if all its methods are non-abstract. (However, if any of >> its methods are abstract, the class itself is required to be abstract.) > > I don't see the point of having an abstract class without abstract methods. > > The main reasons I came up (without knowing C++ allows this too!) with > the idea of giving abstract methods a valid implementation wer (a) > there's got to be *something* in the body; (b) to provide an end point > for cooperative-MI-style code. > >> As someone with more recent background in Java than C++, I find the idea of >> abstract methods having an executable implementation to be quite confusing, >> and suspect that other people with that Java or C# background will do the >> same thing. That is, skim the explanation and miss the significant >> difference between the C++ way and what they're used to. > > Well, too bad. After a day of coding in Java I start typing curly > braces and semicolons too. But that doesn't mean Python should adopt > these. I think I am in (weak) agreement with Phillip here. In every language that I am familiar with, the adjective "abstract" when applied to a method implies two things: (1) that the method does not have a body, and (2) the method must be implemented by a subclass if that subclass is able to be instantiated. In fact, (2) is merely a consequence of (1), when combined with the additional constraint that no instantiated class can have methods with no body. However, I think what is going on is that you're using the word "abstract" in a slightly difference sense. Normally, an abstract method provides merely an interface, in other words it defines the method name, argument types, and return type of a method - and nothing more. What you're doing, I think, is saying that an abstract method provides all those things, and in addition it provides a kind of sketch or outline of what the functionality ought to be. I don't have a problem with that part so much. But in addition there is a sense that you also want these methods to be useful helper functions for base classes to call, but you don't want them to be called directly. In languages such as Java and C++, this is what "protected" is for - methods that aren't available to the outside world, but which can be called by subclasses. So it seems to me -- at least from the standpoint of someone steeped in the mindset of Java / C++ / C# et al -- that you are conflating "abstract" and "protected". In what is considered "good style" for such languages, protected helper methods ought to have different names than the methods which invoke them. So for example, you might have the following: /// Abstract base class for hashable object class Hashable { public: /// Declare abstract hash method virtual int GetHash() const = 0; protected: /// Protected helper method int DefaultHashFunc() { return 0; } }; // A concrete class derived from hashable class MyConcreteClass : public Hashable { public: /// Declare abstract hash method virtual int GetHash() const { return DefaultHashFunc(); } }; Granted, in this particular case the decision to provide a helper function is rather odd. Why go through the trouble of defining DefaultHash() in the base class that simply returns 0, when any non-trivial subclass will provide a real implementation of GetHash() instead of merely forwarding the call to DefaultHash()? But the solution isn't to give Hashable::GetHash() a body. From a C++ programmer's view, there's only two choices: Either Hashable::GetHash() is abstract, or it's not. If it's abstract, then every subclass is required to re-implement it, and giving it a body has no purpose whatsoever; If it's not, then subclasses are allowed to default to its implementation. >>> That the abstract methods are still somewhat useful implementations is >>> mostly to provide a valid (if not necessarily useful) end point for >>> super-calling in cooperative MI schemes. >> Right; I guess my point is that if those "somewhat" useful implementations >> are useful, they're useful, and there's no need to treat the corresponding >> class as "abstract" (in the "non-instantiable" sense) in that case. For >> example, I could pass an Iterable() to something that expected an iterable. > > Perhaps. Though I think it would defeat the purpose of being required > to provide an implementation. If forced to choose, I'd rather remove > the meaningful bodies (and replace them with "raise > NotImplementedError") than remove the @abstractmethod decorators. But > I prefer the current proposal. -- Talin _______________________________________________ Python-3000 mailing list [email protected] http://mail.python.org/mailman/listinfo/python-3000 Unsubscribe: http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com
