[Python-ideas] Re: Conditions for a coherent MI relationship [was Re: Re: mro and super don't feel so pythonic]
R has changed a bit since 2005. My article was from then: https://gnosis.cx/publish/programming/R3.html I'm not trying to quibble about R, but simple to point out that what often mystified as "deep" about OOP is actually banal and fairly trivial. That might be how Alan Kay originally saw OOP. He famously regretted using > the term "object" because it distracted from what he saw as the genuinely > fundamental parts of OOP, namely > > * Message passing > * Encapsulation > * Late (dynamic) binding I like Alan. I worked with him a little bit. I agree with his attitude here. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/SXHA3GUDZ7P5EO6RF3YB5LGGCOHE5XXV/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Conditions for a coherent MI relationship [was Re: Re: mro and super don't feel so pythonic]
On Sat, Apr 16, 2022 at 12:23:10PM -0400, David Mertz, Ph.D. wrote: > R doesn't have inheritance, it's not OOP, R is OOP and always has been. All values, arrays, functions etc in R are objects. Even expressions are objects. And it has inheritance. https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Objects https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Inheritance R has three mechanisms for implementing classes, S3, S4 and Reference classes (unofficially known as S5). All three of them allow inheritance. http://adv-r.had.co.nz/S3.html > One thing I do find a bête noire is the silly claim, that Chris repeats, > that inheritance expresses "Is-A" relationships. "Is-a" is fundamental to the relationship between a class and its instances. Inheritance is orthogonal to that relationship, e.g. Swift only allows single inheritance. Every class can only have a single superclass, which defines what kind of thing the subclass is. But it can inherit from multiple mixins or traits, which allow it to inherit behaviour. In Python, virtual subclassing defines that "is-a" relationship without inheriting anything from the parent class. > The reality is more clear in the actual primary definition of the word > itself: "the practice of receiving private property, titles, debts, > entitlements, privileges, rights, and obligations". That definition is incomplete when it comes to inheritance. If I go to the store and purchase a bottle of milk, I have received private property. That's not inheritance. If I receive a knighthood for slaughtering my monarch's enemies, that is also not inheritance. My obligation to pay taxes when begin to earn income is another thing which I receive but is not inheritance. > In programming, a class > can receive methods and attributes from some other classes. That's all. > It's just a convenience of code organization, nothing ontological. That might be how Alan Kay originally saw OOP. He famously regretted using the term "object" because it distracted from what he saw as the genuinely fundamental parts of OOP, namely * Message passing * Encapsulation * Late (dynamic) binding Purists may also wish to distinguish between subclassing and subtyping. Raymond Hettinger has given talks about opening your mind to different models for subclassing, e.g. what he calls the "conceptual view" vs "operational view" of subclassing. Or perhaps what we might call "parent driven" versus "child driven". https://www.youtube.com/watch?v=miGolgp9xq8 But whether we like it or not, the concepts of subclassing and subtyping are entwined. We model "is-a" concepts using classes; we implement code reuse using classes; we model taxonomic hierarchies using classes. Classes are flexible; they contain multitudes. -- Steve ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/G6KLP7QVS3RXWJYNIEPX22DHJFUA6HZO/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Auto assignment of attributes
The problem of assigning init arguments as attributes has appeared several times in the past ( https://mail.python.org/archives/list/python-ideas@python.org/message/VLI3DOFA5VWMGJMJGRDC7JZTRKEPPZNU/ was the most recent we could find) and is already handled in dataclasses. Lately, discussing this topic with a friend, we thought that using a specific token could be a possible approach, so you could do: class MyClass: def __init__(self, @a, @b, c): pass and it would be analogous to doing: class MyClass: def __init__(self, a, b, c): self.a = a self.b = b Then, you would instantiate the class as usual, and the variables tagged with `@` would be bound to the object: >>> objekt = MyClass(2, 3, 4) >>> print(objekt.b) 3 >>> print(objekt.c) AttributeError: 'MyClass' object has no attribute 'c' We have a working implementation here if anyone wants to take a look at: https://github.com/pabloalcain/cpython/tree/feature/auto_attribute. Keep in mind that we have limited knowledge about how to modify cpython itself, and which would the best places be to do the modifications, so it's more than likely that some design decisions aren't very sound ( https://devguide.python.org/grammar/ and https://devguide.python.org/parser/ were incredibly helpful). Besides the implementation, we would like to know what the community thinks on whether this might have any value. While developing this, we realized that Crystal already has this feature (eg https://github.com/askn/crystal-by-example/blob/master/struct/struct.cr) with the same syntax; which is kind of expected, considering it's syntax is based on Ruby. Random collection of thoughts: 1. If auto-assignment made sense in general, one of the reasons we went for this rather than the decorator approach is that we wouldn't like to have a list of strings that can vary decoupled from the actual argument name. 2. The current implementation of `@` works for any function, not only init. We don't know if this would actually be a desirable feature. 3. It also works with any function in the wild. This mostly allows for monkey-patching to work out of the box: >>> class Klass: ... def __init__(self): ... pass ... >>> def add_parameter(k, @p): ... pass ... >>> Klass.add_parameter = add_parameter >>> objekt = Klass() >>> print(objekt.p) Traceback (most recent call last): File "", line 1, in AttributeError: 'Klass' object has no attribute 'p' >>> objekt.add_parameter(11) >>> print(objekt.p) 11 Again, we are not sure if this is desirable, but it's what made most sense for us at the moment. 4. Adding the `@` token to the argument doesn’t remove the variable from the function/method scope, so this would be perfectly valid: >>> def my_function(k, @parameter): ... print(parameter) >>> my_function(objekt, 4) 4 >>> k.parameter 4 5. We didn’t implement it for lambda functions. Cheers, Pablo and Quimey ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/SCXHEWCHBJN3A7DPGGPPFLSTMBLLAOTX/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Conditions for a coherent MI relationship [was Re: Re: mro and super don't feel so pythonic]
On Sat, Apr 16, 2022, 12:26 PM Chris Angelico > wrote: > A button IS a widget. > A horizontal box IS a box. > A box IS a container. > A container IS a widget. > > Class hierarchies in graphical systems are just as much based on those > is-a relationships as any of those "horrible metaphors" you may have come > across, and they are absolutely to do with programming. Just because you > had a bad teacher, that doesn't mean the concepts are wrong. > Well, more like a few dozen bad books. I never studied any of this with a teacher. But when I teach it (to quite a lot of programming professionals), I never once mention that IS-A stuff, other than maybe curses sotto voce. And mostly they come away saying they finally understood it after my presentation. > ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/5A3J6LRBADRYWC65MXHIQNHPQICLDDIA/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Conditions for a coherent MI relationship [was Re: Re: mro and super don't feel so pythonic]
On Sun, 17 Apr 2022 at 02:23, David Mertz, Ph.D. wrote: > One thing I do find a bête noire is the silly claim, that Chris repeats, that > inheritance expresses "Is-A" relationships. It was torture in the 1990s > hearing about vehicles and trucks and sedans as if that had something to do > with programming. I never "got" OOP for at least 5 years later than I should > have because of those horrible Linnaean metaphors. > A button IS a widget. A horizontal box IS a box. A box IS a container. A container IS a widget. Class hierarchies in graphical systems are just as much based on those is-a relationships as any of those "horrible metaphors" you may have come across, and they are absolutely to do with programming. Just because you had a bad teacher, that doesn't mean the concepts are wrong. ChrisA ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/AXY5ZJORW2CWBCCH5H7MQ6HULUG4DPRT/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Conditions for a coherent MI relationship [was Re: Re: mro and super don't feel so pythonic]
I don't really care what terms like "Full MI" or "True MI" are intended to mean. Python and MANY other programming languages that allow classes to have multiple parents, use a method resolution order (MRO) to decide which same-named method from a complex inheritance tree to use in a given call. If languages use an MRO, C3 is probably the best choice. But not the only one. But sure, C++ and Eiffel are free to refuse "ambiguity" of names occurring multiple times in an inheritance tree. Other languages are free to use single inheritance, or traits, or mixins. I wrote an article a lot of years ago, around the time C3 was new to Python, intending to show what a banal thing OOP is in which I added inheritance and an MRO to R (all within R itself). It was something like 20-30 lines of code in total. My MRO was something dumb like depth first or breadth first, but it WAS an MRO. R doesn't have inheritance, it's not OOP, which was my main reason to choose it for the exercise. One thing I do find a bête noire is the silly claim, that Chris repeats, that inheritance expresses "Is-A" relationships. It was torture in the 1990s hearing about vehicles and trucks and sedans as if that had something to do with programming. I never "got" OOP for at least 5 years later than I should have because of those horrible Linnaean metaphors. The reality is more clear in the actual primary definition of the word itself: "the practice of receiving private property, titles, debts, entitlements, privileges, rights, and obligations". In programming, a class can receive methods and attributes from some other classes. That's all. It's just a convenience of code organization, nothing ontological. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/CSSBRRM42NK7JMLMOEBL7JIY5ITPQC2W/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Conditions for a coherent MI relationship [was Re: Re: mro and super don't feel so pythonic]
On Sat, 16 Apr 2022 at 20:28, Steven D'Aprano wrote: > So please stop falsely accusing me of "No True Scotsman" bullshit. If > you keep doing it, I will know you're not arguing in good faith. Fine. I'll accuse you, instead, of using "full MI" to mean "the best MI system that Steven D'Aprano can conceive". Happy now? Because that is precisely what you are doing. Any argument to the contrary is met with complaints that we need to show that something is *better* for *Python*. For something to be "full MI", in your view, it has to match what Python does, or be objectively better than it, in your personal opinion. I'm not going to bother responding to the rest of the details, as they're all the same argument repeated. ChrisA ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/3UATWEE4ICWWT42QHCW7DE2SLZZ2NDGZ/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sat, Apr 16, 2022 at 05:27:57PM +1200, Greg Ewing wrote: > On 15/04/22 10:37 pm, Steven D'Aprano wrote: > >If you look at languages that implement MI, and pick the implementations > >which allow it with the fewest restrictions, then that is "full MI". > > >I believe that Python (and other languages) allow MI with > >the smallest set of restrictions, namely that there is a C3 > >linearization possible > > But before Python adopted the C3 algorithm, it was less > restrictive about the inheritance graph. Less restrictive, and *inconsistent* (hence buggy). > So by your definition, current Python does not do full MI! No, I'm excluding inconsistent models of MI. Correctness is a hard requirement. Otherwise we get into the ludicrous territory of insisting that every feature can be implemented with one function: def omnipotent_function(*args, **kwargs): """Function which does EVERYTHING. (Possibly not correctly, but who cares?) """ return None There you go, now we can define an MRO for any class hierarchy imaginable, and dispatch to the next class in that hierarchy, using the same function. It won't work, of course, but if correctness isn't a hard requirement, what does that matter? :-) > >If you have to manually call a specific method, as shown here: > > > >https://devblogs.microsoft.com/oldnewthing/20210813-05/?p=105554 > > > >you're no longer using inheritance, you're doing delegation. > > You could also say that Python automatically delegates to the first > method found by searching the MRO. > > Why is one of these delegation and not the other? That is a very interesting question. As I mentioned earlier, there is a sense that all inheritance is a kind of delegation, and in languages without an explicit super() (or "nextclass", or whatever you want to call it), the only way to get inheritance when you overload a method is to use explicit delegation to your superclass. So we might say that all inheritance is delegation, but not all delegation is inheritance. We might even go further and say that any delegation to a superclass (not just the direct parent) is a form of manual inheritance. But in general, in ordinary language, when we talk about inheritance, we're talking about two (maybe three) cases: 1. Automatic inheritance, when your class doesn't define a method but automatically inherits it from its superclass(es). class Parent: def method(self): pass class Child(Parent): pass assert hasattr(Child, "method") 2. Automatic inheritance when your class overloads a method and calls super() manually to delegate to the superclass(es). class Child(Parent): def method(self): print("Overload") super().method() 3. And more dubiously, but commonly used, when people who don't like super(), or know about it, explicitly delegate to their parent in single inheritance: class Child(Parent): def method(self): print("Overload") Parent.method(self) # Oooh, flashbacks to Python 1.5 -- Steve ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/GOMMXQW4L6OJXO2425DZQE5AERGEMC5G/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sat, Apr 16, 2022 at 05:56:13PM +1200, Greg Ewing wrote: > On 16/04/22 12:56 pm, Steven D'Aprano wrote: > >If you exclude models of MI which are logically incoherent and > >inconsistent, (such as Python's prior to version 2.3), then Python's > >model of MI is objectively as complete as you can get. > > You seem to be assuming that "full MI" has to include a fully > automatic means of method resolution. How very observant of you, I only mentioned that about a hundred bazillion times so far!!! (Yes, I am frustrated. But cheerfully so.) > There's nothing incoherent or inconsistent about the way C++ > and Eiffel do MI. Good thing I never said that they were incoherent or inconsistent. I'm happy to have vigorous debate, but it would be kinda nice if people would argue against my actual position. As I understand it, C++ and Eiffel still do automatic method resolution, it is only when there is a conflict that they demand you manually resolve the conflict. > The main difference is that they require you > to explicitly resolve conflicts between inherited methods -- Right, another thing which I have mentioned. In that regard, they are sort of like traits, as developed in Squeak. (Scala traits are something different. Another example of different languages using the same term to mean different things.) > which is arguably more Pythonic than Python, since they refuse > the temptation to guess. There is no *guessing* in the C3 linearization algorithm. -- Steve ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/MJNOGXMDLBVBPGMOJ624AOAJHQ3C3TJJ/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Conditions for a coherent MI relationship [was Re: Re: mro and super don't feel so pythonic]
On Sat, Apr 16, 2022 at 04:40:58PM +1000, Chris Angelico wrote: > > Which conditions would you drop? There's not that many, really. Five. > > Six if you include the "no cycles" requirement for the DAG, which I > > think is so obviously necessary that it is barely worth mentioning. > > This is *exactly* the "no true Scotsman" fallacy: you have already > excluded from consideration anything that drops a condition you didn't > already drop. No, I have excluded them from consideration because if you allow them, **inheritance doesn't work properly**. It becomes inconsistent and buggy. Bad things happen, like the method resolution order depending on how you spell the class name, or differing between a class and its subclass. Maybe those bad things will be rare. MI in Python 1.x only misbehaved if you had a diamond graph, which was rare with classic classes. With new-style classes, all multiple inheritance includes diamonds, and MI in Python 2.2 misbehaved under some circumstances but not all: https://mail.python.org/pipermail/python-dev/2002-October/029035.html For 2.3, we swapped to using a proven algorithm, C3 linearization, to fix those problems. This was not an arbitrary choice. It is necessary to avoid inheritance misbehaving. Like Dylan, Ruby, Perl etc (to the best of my knowledge, corrections are welcome) Python now supports as many cases of automatic inheritance in MI as it is possible to support without breakage. There is no more silent breakage in the MI model like there was in Python 1.5, instead we get a clear exception if we try to create an inconsistent class hierarchy. C++ and Eiffel are even stricter (more restrictive) than Python. They don't just exclude class hierarchies which are inconsistent, they exclude class hierarchies with perfectly good linearizations because they have a method conflict. As I have said now more times than I can count, that's a perfectly acceptible design choice, maybe even better than Python's, but it means that their MI model is less general than Python's. Hard to believe that this mild take is so controversial. Imagine if I had something really wild like "Python lists are mutable" or "cars generally drive on four wheels". > On the assumption that your five conditions are > essential, there's no way that you can drop any of the five conditions > and still have it count, therefore the five conditions are essential. > Your logic is circular. You seem to be determined to accuse me of every fallacy under the sun, whether it applies or not. Excluded middle, No True Scotsman (no matter how many times I say that other choices for MI are legitimate and maybe even better than Python's choice), circular reasoning. At least you haven't (yet) accused me of poisoning the well, perhaps because the irony would be too much. The conditions I have given are not essential because Python has them, but because they genuinely are essential to avoid buggy MI like Python used to have. There are other ways to avoid such bugs. You can do what Java does, and not allow MI at all. Or you can refuse to resolve method conflicts, like C++ and Eiffel. Or you might just hope that nobody notices the bugs, and if they do, close them as Won't Fix. There are many strategies a language might take. > It is highly arrogant to assume that nobody will ever find a way to > implement MI while dropping one of your conditions. They're not > fundamental to the definition, they're fundamental to *the way Python > does things*. No, they are fundamental to the definition. People just don't generally mention them, either because they don't know them, or take them for granted. The three conditions for C3 are necessary for MI to be consistent and coherent. Of course you don't need them if you have subclassing without inheritance (like mixins in some languages), or no MI at all, but otherwise you need C3. The rule that the linearization should only depend on the DAG between classes, and not on incidental factors like their name, or the time of the day, or a random number generator, is just common sense. https://i.imgur.com/fIVQIj8.jpg The requirement for automatic conflict resolution is kinda necessary for it to be inheritance, otherwise you're doing something else. E.g. in Eiffel, you have to rename the conflicting methods. In C++ you have to use explicit delegation. Which is cool. As I have said about a bajillion times now, there are good arguments that the more restrictive models of MI implemented by C++ and Eiffel are better than the less restrictive model used by Python. So please stop falsely accusing me of "No True Scotsman" bullshit. If you keep doing it, I will know you're not arguing in good faith. > > The most subjective is the requirement for automatic conflict > > resolution. It is a legitimate design choice to give up automatic > > conflict resolution (that's what C++ and Eiffel do) but that would be a > > breaking change for Python. > >