{"id":1474,"date":"2021-03-19T10:10:51","date_gmt":"2021-03-18T22:10:51","guid":{"rendered":"http:\/\/p-s.co.nz\/wordpress\/?p=1474"},"modified":"2021-05-01T10:13:39","modified_gmt":"2021-04-30T22:13:39","slug":"second-impressions-of-python-pattern-matching","status":"publish","type":"post","link":"http:\/\/p-s.co.nz\/wordpress\/second-impressions-of-python-pattern-matching\/","title":{"rendered":"Second Impressions of Python Pattern Matching"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Less is More<\/h2>\n\n\n\n<p>One of the beautiful things about Python is its simplicity. We don&#8217;t want it to end up like those languages which have a designed-by-committee feel where everyone gets to add features and there are many ways of doing everything. Every feature that is added not only has to have some value but that value must outweigh the cost of the additional complexity. The more features, the more learning is required before being able to understand and edit other people&#8217;s code; the greater the risk that learning will be broad and shallow; and the larger the bug surface for the language. Simple is good.<\/p>\n\n\n\n<p>In the <a rel=\"noreferrer noopener\" href=\"http:\/\/p-s.co.nz\/wordpress\/first-impressions-of-python-pattern-matching\/\" target=\"_blank\">previous blog post<\/a> I concluded that Pattern Matching was a positive addition to the language. After looking further into the gotchas of Python Pattern Matching, and listening to the arguments of a friend (you know who you are :-)), I have become much less sure. In balance, I suspect Python Pattern Matching probably doesn&#8217;t pass the Must-Be-Really-Valuable-To-Justify-the-Increased-Complexity test.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Arguments Against Python Pattern Matching<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Significant Gotchas<\/h3>\n\n\n\n<p>This section includes some material from the previous blog post but with a different emphasis and more detail.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><em>Similarity to object instantiation misleading<\/em><\/h4>\n\n\n\n<p>Imagine we have a Point class:<\/p>\n\n\n\n<p><code>class Point:<br>    def __init__(self, x, y):<br>        pass<\/code><\/p>\n\n\n\n<p><br><code>case Point(x, y):<\/code> seems to me to be an obvious way of looking for such a <code>Point<\/code> object and unpacking its values into <code>x<\/code> and <code>y<\/code> but it isn\u2019t allowed. It is a perfectly valid syntax for instantiating a <code>Point<\/code> object but we are not instantiating an object and supplying the object the case condition \u2013 instead we are supplying a pattern to be matched and unpacked. We have to have a firm grasp on the notion that Python patterns are not objects. If we forget we get a TypeError:<\/p>\n\n\n\n<p><code>case Point(0, 999):<br>TypeError: Point() accepts 0 positional sub-patterns (2 given)<\/code><\/p>\n\n\n\n<p>Note, we must match the parameter names (the left side) but can unpack to any variable names we like (the right side). For example, all of the following will work:<\/p>\n\n\n\n<p><code>case Point(x=x, y=y):<br>case Point(x=lon, y=lat):<\/code><br><code>case Point(x=apple, y=banana):<\/code><\/p>\n\n\n\n<p>but<\/p>\n\n\n\n<p><code>case Point(a=x, b=y):<\/code><\/p>\n\n\n\n<p>will not.<\/p>\n\n\n\n<p>It is a bit disconcerting being forced to use what feel like keyword arguments in our patterns when the original class definition is optionally positional. We should expect lots of mistakes here and it&#8217;ll require concentration to pick them up in code review.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><em>Similarity to isinstance misleading<\/em><\/h4>\n\n\n\n<p><code>case Point:<\/code>, <code>case int:<\/code>, <code>case str:<\/code>, <code>case float:<\/code> don\u2019t work as you might expect. The proper approach is to supply parentheses: using the example of integer patterns, we need <code>case int():<\/code>, or, if we want to \u201ccapture\u201d the value into, say, <code>x<\/code>, <code>case int(x):<\/code>. But if we don&#8217;t know about the need for parentheses, or we slip up (easy to do) these inadvertant patterns will match anything and assign it to the name <code>Point<\/code> or <code>int<\/code> or <code>str<\/code> etc. Definitely NOT what we want.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"http:\/\/p-s.co.nz\/wordpress\/wp-content\/uploads\/2021\/03\/str_overwritten.png\"><img loading=\"lazy\" decoding=\"async\" width=\"931\" height=\"542\" src=\"http:\/\/p-s.co.nz\/wordpress\/wp-content\/uploads\/2021\/03\/str_overwritten.png\" alt=\"\" class=\"wp-image-1475\" srcset=\"http:\/\/p-s.co.nz\/wordpress\/wp-content\/uploads\/2021\/03\/str_overwritten.png 931w, http:\/\/p-s.co.nz\/wordpress\/wp-content\/uploads\/2021\/03\/str_overwritten-300x175.png 300w, http:\/\/p-s.co.nz\/wordpress\/wp-content\/uploads\/2021\/03\/str_overwritten-768x447.png 768w, http:\/\/p-s.co.nz\/wordpress\/wp-content\/uploads\/2021\/03\/str_overwritten-500x291.png 500w\" sizes=\"(max-width: 931px) 100vw, 931px\" \/><\/a><figcaption>the builtin str is now broken &#8211; hopefully obviously<\/figcaption><\/figure>\n\n\n\n<p>The only protection against making this mistake is when you accidentally do this before other case conditions \u2013 e.g.<\/p>\n\n\n\n<p><code>case int:<br>^<br>SyntaxError: name capture 'int' makes remaining patterns unreachable<\/code><\/p>\n\n\n\n<p>Otherwise you&#8217;re on your own and completely free to make broken code. This will probably be a common error because of our experience with <code>isinstance<\/code> where we supply the type e.g. <code>isinstance(x, int)<\/code>. Which reminds me of a passage in <em>Through the Looking-Glass, and What Alice Found There<\/em> by Lewis Carroll.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>&#8216;Crawling at your feet,&#8217; said the Gnat (Alice drew her feet back in some alarm), &#8216;you may observe a Bread-and-Butterfly. Its wings are thin slices of Bread-and-butter, its body is a crust, and its head is a lump of sugar.&#8217;<\/p><\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>&#8216;And what does <strong>it<\/strong> live on?&#8217;<\/p><p>&#8216;Weak tea with cream in it.&#8217;<\/p><p>A new difficulty came into Alice&#8217;s head. &#8216;Supposing it couldn&#8217;t find any?&#8217; she suggested.<\/p><p>&#8216;Then it would die, of course.&#8217;<\/p><p>&#8216;But that must happen very often,&#8217; Alice remarked thoughtfully.<\/p><p>&#8216;It always happens,&#8217; said the Gnat. After this, Alice was silent for a minute or two, pondering.<\/p><\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">Summary<\/h3>\n\n\n\n<p>There will be lots of mistakes when using the match case even in the most common cases. And more complex usage is not readable without learning a lot more about Pattern Matching. See <a rel=\"noreferrer noopener\" href=\"https:\/\/www.python.org\/dev\/peps\/pep-0622\/\" target=\"_blank\">PEP 622<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"http:\/\/p-s.co.nz\/wordpress\/wp-content\/uploads\/2021\/03\/match_case_mini_language.png\"><img loading=\"lazy\" decoding=\"async\" width=\"531\" height=\"208\" src=\"http:\/\/p-s.co.nz\/wordpress\/wp-content\/uploads\/2021\/03\/match_case_mini_language.png\" alt=\"\" class=\"wp-image-1476\" srcset=\"http:\/\/p-s.co.nz\/wordpress\/wp-content\/uploads\/2021\/03\/match_case_mini_language.png 531w, http:\/\/p-s.co.nz\/wordpress\/wp-content\/uploads\/2021\/03\/match_case_mini_language-300x118.png 300w, http:\/\/p-s.co.nz\/wordpress\/wp-content\/uploads\/2021\/03\/match_case_mini_language-500x196.png 500w\" sizes=\"(max-width: 531px) 100vw, 531px\" \/><\/a><figcaption>Readable but only if you understand the mini-language<\/figcaption><\/figure>\n\n\n\n<p>Basically it is a yet another mini-language to learn.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Arguments for Python Pattern Matching<\/h2>\n\n\n\n<p>Sometimes we need to pattern match and a match \/ case syntax is quite elegant. The way values are unpacked into names is also really nice.<\/p>\n\n\n\n<p>We will certainly love this feature if we are moving away from duck typing and adopting the programming style of statically-typed languages like Scala. But maybe we shouldn&#8217;t encourage this style of programming by making it easier to write in Python.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Verdict<\/h2>\n\n\n\n<p>In balance, Python Pattern Matching doesn&#8217;t seem to pass the Must-Be-Really-Valuable-To-Justify-the-Increased-Complexity test. And I&#8217;m not alone in wondering this (<a href=\"https:\/\/nicolaiarocci.com\/musings-on-pythons-pattern-matching\/\" target=\"_blank\" rel=\"noreferrer noopener\">Musings on Python&#8217;s Pattern Matching<\/a>). I enjoyed coming to grips with the syntax but I think it is like <code>for else<\/code> and Python Enums &#8211; best avoided. But we will see. We can&#8217;t always tell what the future of a feature will be &#8211; maybe it will turn out to be very useful and one day there will be a third blog post ;-).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Less is More One of the beautiful things about Python is its simplicity. We don&#8217;t want it to end up like those languages which have a designed-by-committee feel where everyone gets to add features and there are many ways of &hellip; <a href=\"http:\/\/p-s.co.nz\/wordpress\/second-impressions-of-python-pattern-matching\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,3],"tags":[26,15,25,27],"class_list":["post-1474","post","type-post","status-publish","format-standard","hentry","category-programming","category-python","tag-pattern-matching","tag-python","tag-python3","tag-python3-10"],"_links":{"self":[{"href":"http:\/\/p-s.co.nz\/wordpress\/wp-json\/wp\/v2\/posts\/1474"}],"collection":[{"href":"http:\/\/p-s.co.nz\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/p-s.co.nz\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/p-s.co.nz\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/p-s.co.nz\/wordpress\/wp-json\/wp\/v2\/comments?post=1474"}],"version-history":[{"count":4,"href":"http:\/\/p-s.co.nz\/wordpress\/wp-json\/wp\/v2\/posts\/1474\/revisions"}],"predecessor-version":[{"id":1490,"href":"http:\/\/p-s.co.nz\/wordpress\/wp-json\/wp\/v2\/posts\/1474\/revisions\/1490"}],"wp:attachment":[{"href":"http:\/\/p-s.co.nz\/wordpress\/wp-json\/wp\/v2\/media?parent=1474"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/p-s.co.nz\/wordpress\/wp-json\/wp\/v2\/categories?post=1474"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/p-s.co.nz\/wordpress\/wp-json\/wp\/v2\/tags?post=1474"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}