On 29/06/20 8:47 am, Daniel Moisset wrote:
You seem to be trying to shoehorn all Python data structures into looking like alebraic types, for the sole purpose of being able to claim that PEP 622 is really about algebraic types rather than pattern matching.
I don't think that's a helpful way of looking at things. Pattern matching with destructuring is a more general concept. Algebraic types is just one of its applications.
I think your viewpoint is coloured by languages in which algebraic types play a much more central role than they do in Python. For example, in Haskell, the usual notation for lists is syntactic sugar for an algebraic type representing a linked list.
But Python lists are not linked lists, they're flexible-sized arrays, and you have to squint very hard indeed to see them as being fundamentally an algebraic type. Yet pattern matching on them makes perfectly good sense.
returning by default an object __dict__ or some sort of mapping view on the attributes could still be fine. It's not clear to me why the "keys" of this structure are placed separately.
I think the PEP explains the rationale behind the design of the matching protocol quite well. The goal is to make it as simple as possible to implement in the most common cases.
For me, there should be an instance method in object (that subclasses can override) that returns the algebraic structure of the value. The PEP as-is creates different destructuring views depending on which matching class you use (whicch I think relates to something that was mentioned but not discussed a lot in the python-dev list about Liskov sustitability).
I think the PEP has this right. Liskov substitutability doesn't apply to constructors -- they're not methods, and the constructor of a subclass doesn't have to accept the same arguments as that of its base class. The same thing applies to deconstructors, since they have to mirror the signature of their corresponding constructors. For example, consider
class Oval: def __init__(self, centre, width, height): ...
class Circle(Oval): def __init__(self, centre, radius): ...
match shape: case Oval(c, w, h): ...
If shape happens to be a Circle, you still want to deconstruct it as an Oval and get centre, width, height, not centre, radius. There's no way that can happen if the object itself is responsible for its deconstruction.
(Incidentally, I do think the post that mentioned Liskov substitutability has a point, but it's a different one -- the default single-positional-argument deconstruction is probably a bad idea, because it will be wrong for a large number of existing classes.)