
On Tue, 20 Dec 2022 at 12:55, Ethan Furman <ethan@stoneleaf.us> wrote:
On 12/19/22 13:59, Chris Angelico wrote:
The way things are, a StrEnum or an HTML string will behave *exactly as a string does*. The alternative is that, if any new operations are added to strings in the future, they have to be explicitly blocked by StrEnum or else they will randomly and mysteriously misbehave - or, at very best, crash with unexpected errors. Which one is more hostile to subclasses?
As Brendan noted, mixed-type enums are special -- they are meant to be whatever they subclass, with a couple extra features/restrictions.
Fair, but defaultdict also exhibits this behaviour, so maybe there are a number of special cases. Or, as Syndrome put it: "When everyone's [special]... no one will be."
Personally, every other time I've wanted to subclass a built-in data type, I've wanted the built-in methods to return my subclass, not the original class.
All of which is to say: sometimes you want it one way, sometimes the other. ;-)
Yep, sometimes each way. So the real question is not "would the opposite decision make sense in some situations?" but "which one is less of a problem when it's the wrong decision?". And I put it to you that returning an instance of the base type is less of a problem, in the same way that *any other* operation unaware of the subclass would behave. def underline(head): """Build an underline line for the given heading""" return "=" * len(head) Would you expect underline() to return the same type as head, or a plain str? Would this be true of every single function that returns something of the same kind as one of its parameters?
Metaclasses, anyone?
Hmm, how would they help? I do think that metaprogramming could help here, but not sure about metaclasses specifically. If I wanted to automate this, I'd go for something like this: @autospecialize class Str(str): def extra_method(self): ... where the autospecialize decorator would look at your class's first base class, figure out which methods should get this treatment (only if not overridden, only if they return that type, not __new__, maybe other rules), and then add a wrapper that returns __class__(self). But people will dispute parts of that. Maybe it should be explicitly told which base class to handle this way. Maybe it'd be better to have an intermediate class, rather than mutating the subclass. Maybe you should be explicit about which methods get autospecialized. It's not an easy problem, and simply returning the base class is the one option that you can be confident of. ChrisA