|
|
Subscribe / Log in / New account

Not coalescing around None-aware

Not coalescing around None-aware

Posted Dec 23, 2022 0:14 UTC (Fri) by shironeko (subscriber, #159952)
Parent article: Not coalescing around None-aware

The existing construct
if x is None:
x = 42
is already pretty readable and concise, and the only problem people seem to have with it is that it is required "too often" right?
So IMO it could be solved by looking at all the situations where this is required and improve the language so the most common use-case for checking for None isn't even needed. In fact python already have things that do this optimization, imagine how annoying this None check problem would be if python didn't have foo(arg=Default) for optional arguments. So introducing similar features could eliminate this None problem and probably do more good to readability than any possible operator name people can think of.


to post comments

Not coalescing around None-aware

Posted Dec 23, 2022 9:17 UTC (Fri) by ceplm (subscriber, #41334) [Link] (2 responses)

My problem with these operators (and a lot of what already happened to Python in the last few releases) is that it is similar to the Java discussion on the checked exceptions: it is completely dominated by people who didn’t understand the problem and they are trying to get rid of something which they consider just an annoyance.

For me all those if foo is None are code smell: a sign of poorly created API (perhaps unavoidable, because introduced from an external library). Similarly to the checked exceptions, when you start to look for improved syntax which would get rid of if is None then reconsider whole code around the problem and you may find that you need restructure it to express your algorithm better.

Not coalescing around None-aware

Posted Dec 23, 2022 11:05 UTC (Fri) by adobriyan (subscriber, #30858) [Link] (1 responses)

There is Python gotcha where default class member values are global:

class X:
l = []

x1 = X()
x2 = X()
print(x1.l, x2.l)
x1.l.append(1)
print(x1.l, x2.l)

results in

[] []
[1] [1]

so passing None as default value in constructor is obvious solution. I'm not sure how often this is seen in practice but not code smell for sure.

Not coalescing around None-aware

Posted Dec 23, 2022 11:49 UTC (Fri) by smurf (subscriber, #17840) [Link]

> not code smell for sure

Well, "language smell" then – as there really should be a way to instantiate the default option(s) at the time they are needed, not when the "def" statement is compiled.

Attempts to add a way to do this to Python have not succeeded so far.

Not coalescing around None-aware

Posted Dec 23, 2022 20:15 UTC (Fri) by iabervon (subscriber, #722) [Link] (1 responses)

I think this particular example comes from a language design anti-pattern, where, in order to introduce a feature, you present the simplest case in which you could use it. It seems like an easy way to show what the feature can do, but changing the language is not worthwhile just to make a simple statement slightly simpler. There's a value in not repeating an expression, but it's hard to appreciate if the example expression is a single-character variable name.

Consider: "if we're told to check size limits, and the size of the message's header, if any, plus the size of the message's body, if any, is greater than the limit, raise an exception". (And the message representation might be using complicated objects for header and body that may be expensive to get the length of if it isn't needed, and want to clearly distinguish the case of not having a body or header in other places by using None to represent this situation.) That's:

if check_size_limits and (len(message.header ?? "") +
                          len(message.body ?? "")) > limit:
    raise Exception()

With the feature, and:

if check_size_limits:
    header_length = 0
    if message.header is not None:
        header_length = len(message.header)
    body_length = 0
    if message.body is not None:
        body_length = len(message.body)
    if header_length + body_length > limit:
        raise Exception()

Or:

if check_size_limits and ((len(message.header) if message.header is not None else 0) +
                          (len(message.body) if message.body is not None else 0)) > limit:
    raise Exception()

With the feature, you can write something much closer to the specification, and if the next version of the code has to add "likewise for the message's footer", the programmer who copies the "header" section and changes "header" to "footer" can't miss the second place that "header" appeared. Furthermore, the first one consists entirely of text you'd want to read in order to understand what it's doing, while the others have portions you'd skim, and hope that they correctly implement "if necessary". Similarly, "(some long but descriptive expression)?.attribute" is much easier to understand than "(some long but descriptive expression).attribute if (probably the same thing but maybe not) is not None else None", while "x.y if x is not None else None" isn't worth the trouble.

That said, I find the operator "??" doesn't feel Pythonic to me, and I think some short word would fit the Python better, but I can't think of a word that would suit; "?." also seems weird, but I can't think how to avoid using a weird symbol when the basic expression uses as operator already.

Not coalescing around None-aware

Posted Dec 23, 2022 20:48 UTC (Fri) by shironeko (subscriber, #159952) [Link]

How about just have message return it's proper serialized length, maybe with caching so the length check is efficient everywhere you need it and you avoid having to leak the header body footer logic to every call site which will get hard to maintain fast.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds