Continuing the discussion from PEP 802: Display Syntax for the Empty Set:
In the other thread, @matthewyu0311 made a suggestion about pass
as an expression that I thought was cool[1]. This change would be backward-compatible in that pass
could still be used everywhere it’s currently used, but it would also open doors to cute inline things like subprocess.run(["command", "--debug" if debug else pass])
(a variant of code suggested by @bwoodsend in the other thread).
I have a hard time thinking about things like this in the abstract, though, so I spent some time today hacking at an implementation. The resulting code is a disgusting hacky mess and definitely doesn’t handle all edge cases, but it did let me get a sense for how this might feel in practice.
In case anyone else is interested, I’m sharing an Emscripten-based demo of the implementation (source at adqm/cpython:pass_expression if anyone wants to compile for themselves, but please don’t judge the code too harshly ). Here is what I tried to implement:
-
pass
becomes a built-in constant likeNone
. -
pass
cannot be added to alist
ortuple
orset
; trying to do so will cause that entry to be (silently) ignored. So, for example,[1, 2, 3 if False else pass, 4] == [1, 2, 4]
. -
Similarly,
pass
cannot be added as a key or a value in adict
. So, for example,{1: 2, 3: pass, pass: 6} == {1: 2}
. -
If
pass
is provided as an argument (positional or keyword) to any function call, it’s ignored as well. Soprint(1, pass, 3, file=pass)
is equivalent toprint(1, 3)
. -
So that I could try out some of the other suggestions from the thread, I added
/
as an alias forpass
. So in the demo,{/} == {pass} = set()
.
To be clear, though, I’m not actually proposing that this change be made, just sharing some thoughts and code.
I do think there’s something cool here. When used in the right way, [expr if cond else pass]
feels to me like a very natural extension of what we already have.
But after trying it out some more, I’m pretty much convinced that this is too weird to be considered seriously, at least without some adjustments to the semantics I implemented above. Maybe it would feel normal after enough time, but for now I don’t think it feels like the natural extension of the language that I was hoping for.
Here are a couple of things that weirded me out a little bit at first even though they’re natural consequences of the semantics described above:
>>> pass
pass
>>> print(pass) # no output
>>> type(pass)
Traceback (most recent call last):
File "<python-input-11>", line 1, in <module>
type(pass)
~~~~^^^^^^
TypeError: type() takes 1 or 3 arguments
>>> x = pass
>>> x
Traceback (most recent call last):
File "<python-input-19>", line 1, in <module>
x
NameError: name 'x' is not defined
It also reminded me of another old thread ↩︎