Initializer for set, like dict {} and list []

That would be a joy to read but a pain to write with most keyboards.

ASCII art like {/} or (/) would be friendly to both read and write.

4 Likes

Would have to measure to figure out whether it’s actually worth the effort, but this is at least theoretically possible. The optimizer has all the information it needs to do this. That would NOT be possible with set() due to the potential for shadowing.

(Imo it would be pretty reasonable for python to elevate part/all of the buitins to a special status that are assumed to not be shadowed to allow such optimizations - but that’s a different FR)

2 Likes

That would be a breaking change and an unpopular one. You can and should be able to use those names in your own code. I don’t know when I would do it with set, but I have at times done something like this:

_print = print
def print(*a, **kw):
    if "file" not in kw: kw["file"] = sys.stderr
    _print(*a, **kw)

This wouldn’t be possible if I couldn’t shadow print (and is one of the reasons it became a plain function rather than a language keyword). Like I said, I’ve never personally done this with set() [1], but the option is there and it would be a pain to revoke it.


  1. that I can recall, anyhow ↩︎

2 Likes

Yeah, print should probably not be part of this elevated set - but I still think others, like set could be (imo, the fact that you don’t recall ever wanting to overwrite it is evidence for this). I would probably start conservative and only do this set and dict if there is no write access to them in the current file or something like that.

A lot of existing code would break though, including some in CPython:

2 Likes

Why should some be special and others not? What would be the boundary? It would be highly confusing - a small collection of names that can’t be overridden, but are otherwise normal names? And what if you do something like globals()["set"] = ... or exec("set()", {"set": some_function}) - would that be disallowed?

I don’t think it’s a good path to go down.

1 Like

The special treatment did happen to True and False with Python 3. The change didn’t break a lot of code though since there aren’t many if any other way in English to interpret True and False as anything else so people don’t tend to reassign them. set however has quite a few meanings other than a mathematical set so the impact of a keywordization would be much larger.

1 Like

Ah, that’s slightly different. They became keywords - in effect, a new kind of boolean literal. They’re not regular names any more. Doing that would have even stronger backward compatibility issues, although it would at least avoid the confusion of “name, but not shadowable”.

With the description I used and you quoted, neither of these would break.

1 Like

You mean this? It’s a bit magical:

Which of these counts as “write access”?

globals()["set"] = ...

setattr(sys.modules[__name__], set.__name__, ...)

sneaky_module.update_my_globals("set", ...)

Etcetera. If you’re going to call it an optimization, these will break it (and bear in mind that injection into another module is a common way of implementing tests, so these aren’t as contrived as they look). OTOH, if you want to make it a part of syntax, it’s going to need to be clearly defined.

Making set into a keyword would definitely be less magical. But unlike True and False, there’s far more breakage and far less benefit.

Ah, I now see what you mean by “if there is no write access to them in the current file”. That’s going to be hard to determine if the write access is done indirectly as @Rosuav pointed out.

None of those (IMO obviously). But I don’t think there is much value in continuing this discussion here - maybe I will write out a proper proposal at some point.

From all ideas so far I like {/} most.
Visual reference is pleasing.

6 Likes

+1 on {/} since it’s probably as close to the official unicode representation of the empty set (U+2205, ∅) as we can get.

I think it also fits in nicely with the existing non-empty set literals:

empty = {/}
one = {"a"}
two = {"a", "b"}
8 Likes

+1 on {/}

2 Likes

I also like the {/} proposal.

Perhaps to allow optional disambiguation {:} could then be additionally recognised as an empty dict? Naturally the current {} must be retained too to avoid breaking a billion lines of code.

5 Likes

Adding just an alias is pretty weak argument but regardless I think that’s an entirely seperate topic that deserves its own thread if a set literal ever gets added.

You’re probably right. Rather than it just being an alias, I thought that maybe {} could be gradually deprecated in favour of {:} over a long period, but that’d probably see pushback.

And yeah, it should be considered a separate issue. I think {/} is clear enough on its own (even a beginner would realise it’s not dict syntax) that confusion is fairly unlikely.

1 Like

{/} is a bug today because s = {1/2} is valid. In general, s = {expression} is valid.