`frozenset` and `frozendict` comprehensions

Updated proposal:

frozenset

  • Empty: frozenset()
  • With items: ${1, 2}
  • Comprehension: ${x for x in range(10)}

frozendict

  • Empty: frozendict()
  • With items: ${1: 2, 3: 4}
  • Comprehension: ${x: 1 for x in range(1)}

Main motivation:

  • Simplicty: we want to endorse immutable objects usage, especially for free-threading and subinterpreters. Simple syntax propomotes this
  • Performance: we don’t want to create intermediate objects to create a builtin type. Special syntax allows to optimize this perfectly

In my opinion there are several important questions if we want to start working on this.

  1. I decided to go with $ (because immutablity is the real deal). It does not look similar to anything else, like f{} looks similar to f'', it can be scaled to $(x for x in range(2)) which would mean tuple comprehension, if we would want this. It can be also added to other data types in the future. While f can’t be used in cases like f[] and f(), because it is a valid syntax already.
  2. Should we really go for empty object literals? Looks like set(), frozenset() and frozendict() calls can be good enough as the empty objects. I propose limiting the scope of this proposal to literals and comprehensions only. We can later address the empty objects separately in the next proposal. It would be easier to get the approvals for the smallest piece of new syntax :slight_smile:
  3. How it should be implemented technically. Currently, there’s an optimization built on top if INTRINSIC for INTRINSIC_BUILD_FROZENSET. Should we build new opcodes or go for INTRINSIC? Should we plan for any future optimizations beforehand?
  4. What C-API would we need? This is a very hot topic for PyFrozenDict API. Currently it does not have a way to build objects interactively. So, we would first likely need to add PyFrozenDict_FromDictSteal API to make a dict with existing APIs and convert it to frozendict the most efficient way. This is the case because PyDict_* mutation APIs can’t be used with PyFronzenDict. The same is not the case for frozenset, it can use mutating PySet_* APIs.
  5. Analyze potential syntax conflicts in lexer / parser with f prefix for strings / frozen objects (if we decide to go with this prefix)
  6. Provide perf numbers: how much faster we can optimize the workflow with our design, compared to older forms like frozendict({1: 2}) and frozenset(x for x in range(10))
  7. Find other core devs who would like and support this idea :slight_smile:

Everyone’s feedback is welcome! :waving_hand:

13 Likes