I’m going to focus on the traversal parts here, because I do think they are much more problematic than presented. I don’t particularly care for ??
and would prefer people stop using None
in function results + gain late-bound defaults, but I’d also probably use ??
if given it.
While I can see an argument for .?
behaving as shown in typescript, where type checking is required to get any use out of it, I don’t think this works particularly well for developers in even just vanilla javascript, and I don’t think it would work well in python, with an optional type system that supports more than structural typing.
Unless you’re suggesting that static typing is required for a first-class experience with new features in python, this isn’t actually any different than getattr is, and I think this is actually an argument against the feature.
Even for those who like type checking and use it, there are existing places with type checking where python type checkers currently produce the wrong results due to poorly defined interactions between structural subtyping and nominal subtyping. There are even existing cases of optional members of the data model that type checkers don’t handle correctly yet. While I use static analysis where I can, it’s nowhere near good enough in python to rely upon to catch all type issues, and some of the largest issues right now are due to incorrect simplifications with structural typing.
The closest we can get right now to undefined in TS is in dicts (missing key-value pairs), and in a specific case with slotted classes that most people would consider a programming error to write intentionally. dicts, we have a means to do this already with .get
, and I’m not really convinced that the syntax is more intuitive and a win for brevity. Over several discussions, people have had various opinions about what errors should and shouldn’t propagate, and even when discussing a concrete proposal, there have been multiple misuses of the proposed operator used in examples people have written to discuss with.
The slotted class version still raises an error, but it’s as close as you can get for an instance of a class to the ts example, where it’s still a static member (inspect.getmembers_static agrees that it is at runtime as well), and where static analysis should apply.
>>> class Example:
... __slots__ = ('a', 'b')
...
>>> 'a' in dict(inspect.getmembers_static(Example))
True
>>> Example().a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Example' object has no attribute 'a'
It seems to be that the people who see a use of it have a use that is largely rooted in handling json data without actually validating it and turning it into python objects. While I don’t want to just say “don’t do that then”, it does seem like we have a number of relatively mature options both in the standard library, and a few outside of them that people could be using instead, both for just traversal (eg. glom) and also for robust structuring of data (eg. msgspec, pydantic, attrs + cattrs, mashumaro)
Is there a strong use case for this outside of handing json data? The only arguments I’ve seen for the traversal portions (.?
and []?
) involve externally sourced json data.
If it’s primarily this, I think we should point people to the existing libraries that help here, and consider adding something to the json module for jsonpath support. Possibly also something to the dataclasses module to parse json into dataclasses, and then put the rest of the focus on the less controversial ??
for a more immediate set of “wins”