8 ms·
PEP 505 – None-aware operators (2015)
- musicale 4y ago?? looks like decent shorthand for: bar if foo is None else foo or perhaps more clearly: foo if foo is not None else bar Seems like it would save some typing.
- kryptn 4y agoI'm glad this was deferred because those replaced examples from the stdlib are difficult to read. I've used `or` coalescing plenty of times and definitely prefer it to a new operator. That said, I really loved using null coalescing/propagation in C#, so I have to assume my bias is coming from wanting python to be more readable.
- dragonwriter 4y agoOr-coalescing can work fine for things that can either be None or truthy, but Python (unlike, say, Ruby) has fairly expansive falsey values, which create lots of places where None coalescing would work but or-coalescing doesn't.
- ghshephard 4y agoI love the walrus operator - and use it quite a bit, but, replacing if hi is None: hi = len(a) With: hi ??= len(a) Just sounds gratuitous. I'm happy this was deferred.
- asperous 4y agoIt's actually simpler then that hi = len(a) if hi is None else hi
- pansa2 4y agoYour `if-else` is more complex than the original that just uses `if`.
- eru 4y agoThe line itself is longer, but the idiom in the original uses mutation, which requires reading more adjacent lines to understand and make sure you haven't missed anything. (In the concrete example, both versions use mutation.)
- pansa2 4y agoI'm not sure I understand. Could you give a concrete example where only one version uses mutation?
- dragonwriter 4y agoAny example that does what the proposed ??= operator does, which is inherently conditional mutation, will use mutation. You can get examples equivalent to the proposed None-coalescing ?? operator does that don't use mutation, though.
- deleted 4y ago[deleted]
- thamer 4y agoThere's a major difference though: `value if predicate else alternative` is itself a value, something you can assign to a variable or pass to a function as a parameter.
- pansa2 4y agoThe examples in that PEP range from pointless (`if hi is None: hi = len(a)` => `hi ??= len(a)`) to cryptic (`libpaths = libpaths?.split(":") ?? []`). Remember the Zen of Python: “Readability counts”.
- phailhaus 4y agoThat latter "cryptic" example is exactly what Typescript looks like in some cases. But there, it works because the type system is guaranteeing you the correct return type, and can warn you when it's unnecessary. To add it to Python would be a huge mistake, because it would encourage throwing in ?'s everywhere "just in case", making it even harder to understand what's being passed around.
- pansa2 4y agoThe `?` operators also fit better within TypeScript's overall syntax, whereas Python traditionally prefers English words over punctuation characters. In a language which considers `and` and `or` more readable than `&&` and `||`, surely `is not None` is more readable than `??`.
- phailhaus 4y agoTrue, but it is tricky because `is not None` doesn't work here. For example, `my_var ?? 0` would become `my_var if not None 0` which doesn't really make sense and also collides with the pre-existing ternary syntax (`my_var if not None else 0`).
- hexane360 4y agoI think this would actually be a good addition. I'd like to use 'or' more often, but it always makes me stop to think "Could this get passed a falsey value?" I've seen a lot of Python bugs because people used "x or 5" when they needed the much uglier "5 if x is None else x".
- kazinator 4y agoThat's like Lisp versus Scheme: Lisp: (or x 5) Scheme: (if (null? x) 5 x)
- ok_dad 4y agoMaking anything other than false and none falsy was a mistake; it’s much easier in Lua, for example, there you just say “x or 5” because only nil and false are falsy.
- pansa2 4y ago> Making anything other than false and none falsy was a mistake Yes. That's how you end up with messes like this one: https://lwn.net/Articles/590299/ https://lwn.net/Articles/590299/
- parentheses 4y agoWhattttttttt?!? TIL!
- dtech 4y agoIt's no longer the case, was changed in Python 3.6
- just_boost_it 4y agoWow! That's UTC as well, so where I am it'd be like having an exception for exactly 4pm, it wouldn't even occur to me that it was a zero!
- eru 4y ago
- fastcall___ 4y agoI like this but I cheated on python with typescript and rust, and I don't think I'm coming back, so I don't think my vote is appropriate.
- ddejohn 4y agoRecently did the same. TypeScript's type system is amazing. Shame I hate JavaScript so much.
- eru 4y agoHack's typesystems is similar-ish. They are both basically what you get when you retrofit something a bit like Haskell's typesystem onto dynamic languages.
- parentheses 4y agoTrade offs. Not > / <..
- LeafItAlone 4y agoRust is great. But you just listed 3 programming languages that each have their own purpose and place!
- throwaway5959 4y agoIt’s hard to imagine what you couldn’t build with those three. (Certain vendor locked systems notwithstanding).
- davesque 4y agoDidn't realize this was a PEP but I'm glad it was deferred. I have a bit of PTSD from my foray into Haskell and trying to understand the internals of libraries like attoparsec. The proposed `??` operator makes me think of things like the `<*>` operator for applicatives. The average person's intuitions don't serve them in guessing at the meaning of either. And extra syntaxey characters really disrupt the flow of things. But I guess that's just my opinion. In any case, this feels like something that belongs in Ruby more than Python. The designers of Python made the deliberate choice of sacrificing conciseness for readability in certain cases. If we give that up, I think Python will end up feeling like something that doesn't know what it wants to be.
- eru 4y agoKeep in mind that in Haskell all operators can be defined in user-level code. They can also be shadowed by your own code. If you don't like `<>`, you can also easily make your own function and use that instead: my_function a b = a <*> b I agree that (infix) operator syntax can make some code hard to read, but it can also make some code easier to read. I do feel strongly that allowing people to make up new operators is preferable to undisciplined overloading of existing operators: Eg in Haskell when you see `<>` at least you know that something unusual might be going on. In C++, when you see `>>` (or even `+`) you have no clue whether it's just plain old bit-shifting, or whether someone overloaded it to do IO or perhaps launch the missiles.
- driggs 4y agoPlease also let me use it as a type hint! `str?` would be much nicer than `Optional[str]` or (new in 3.10) `str | None`
- jonypawks 4y agoAs of 3.10 you can use "str | None" instead of "Optional[str]".
- deleted 4y ago[deleted]
- btown 4y agoFor comparison, here are the Javascript RFCs for the equivalent operators: https://github.com/TC39/proposal-optional-chaining https://github.com/TC39/proposal-optional-chaining https://github.com/tc39/proposal-nullish-coalescing https://github.com/tc39/proposal-nullish-coalescing IMO optional chaining is a lifesaver when dealing with deeply nested JSON, and it's become indispensable in our Typescript code. But we also deal with JSON from various third-party endpoints in Python, and far too often we resort to an inefficient deep_get utility to make our code sensical. > if json?.get("foo")?.get("bar")?[0]?.get("baz") may seem messy but would be infinitely better than the fragile (note the nested list-of-a-single-dict, and how bugs can appear if it's not there): > if json.get("foo", {}).get("bar", [{}])[0].get("baz") or the inefficient > if deep_get(json, "foo.bar.0.baz") It's not nearly as good as the Typescript json.foo?.bar?.[0]?.baz - but it's good enough!
- siproprio 4y agoThey rejected the exception aware operator, it would’ve been the most useful application.